2017-08-17 114 views
0

我有一個選擇查詢,它在具有相同結構(列和主鍵,它們具有不同非聚簇索引)的兩個表上使用UNION ALL關鍵字。這兩個表格包含3900萬行,其中一個是100萬,另一個是3800萬。當僅在table1上運行具有一百萬行的查詢時,大約需要0.2秒,在table2上,根據DB的壓力,我們有不同的情況,最多需要0.5到1.2秒。SQL Server UNION ALL合併連接(連接)太慢

實際上,爲了顯示我需要聯合這兩個表,但問題是聯合查詢需要高達8秒才能運行。當看執行計劃時,最重的操作是Merge Join (Concatenation),成本爲91%,我有點擔心,因爲我正在運行的WHERE子句從table1中選擇51個條目,並從table2(大表中)選擇0個條目。

我無法理解它,我一直試圖找到解決我的問題的最後兩天現在,我發現的所有或者是UNION而不是UNION ALL或不需要的子句正在就位GROUP BYLEFT/INNER JOINS。查詢也進行分頁,使用這個命令ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;,所有測試(在單個表格上和使用UNION ALL)都使用分頁(OFFSETFETCH NEXT)關鍵字進行。

如果需要,我可以提供表詳細信息和查詢詳細信息。它是一個簡單的select查詢,其中2 INNER JOINS和2 LEFT JOINS所有連接的表包含非常少量的數據(範圍從50個條目到20K個條目)。


這裏的查詢

SELECT * 
FROM  (SELECT tr.Id, 
     tr.Amount, 
     tr.TypeId, 
     t.Name AS [Type], 
     tr.Date, 
     tr.ExternalKey, 
     tr.ExternalDescription, 
     tr.GameId, 
     tr.GameProviderId, 
     gp.Name AS GameProvider, 
     u.Username, 
     u.Pincode, 
     gp.Name, 
     g.GameName, 
     u.OperatorId, 
     tr.BalanceBefore, 
     tr.BalanceAfter, 
     tr.UserId 
FROM ( 
     SELECT * 
       FROM  dbo.ActiveTransactions at 
       WHERE (1 = 1) 
     AND ([Date] >= '2017-07-17 20:00:00') 
     AND ([TypeId] != 10) 
     AND ([UserId] = 29041) 
       UNION ALL 
       SELECT * 
       FROM  dbo.TransactionHistory th --WITH(INDEX(IX_TransactionHistory_DateType_UserId)) 
       WHERE (1 = 1) 
     AND ([Date] >= '2017-07-17 20:00:00') 
     AND ([TypeId] != 10) 
     AND ([UserId] = 29041) 
      ) AS tr 

INNER JOIN dbo.Users u ON tr.UserId = u.Id 
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id 
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId 
INNER JOIN dbo.Types t ON tr.TypeId = t.Id ) AS t 
ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY; 
+0

段落是什麼?我會包含這些查詢。 – Dimitri

+0

考慮在聯合之前分別重複聯合和過濾activetransactions和transactionhistory,然後聯合結果。這應該採取。2 + .5到1.2,並在2秒內完成。它會保存聯合動作,直到數據被過濾。 – xQbert

回答

0

這是一個受過教育的猜測:沒有索引或執行計劃的什麼發動機實際上是陷入了知識。

考慮:在連接/過濾器之後而不是之前執行聯合:您必須重複聯接,但是您可能會在聯合集處理中損失一些索引效率。

在這種情況下,我創建了兩個CTE,然後將它們聯合起來。

因爲我無法真正測試這個,我可能有一些語法錯誤。

WITH cte1 AS 
(SELECT tr.Id, 
     tr.Amount, 
     tr.TypeId, 
     t.Name AS [Type], 
     tr.Date, 
     tr.ExternalKey, 
     tr.ExternalDescription, 
     tr.GameId, 
     tr.GameProviderId, 
     gp.Name AS GameProvider, 
     u.Username, 
     u.Pincode, 
     gp.Name, 
     g.GameName, 
     u.OperatorId, 
     tr.BalanceBefore, 
     tr.BalanceAfter, 
     tr.UserId 
FROM ( 
     SELECT * 
       FROM  dbo.ActiveTransactions at 
       WHERE (1 = 1) 
     AND ([Date] >= '2017-07-17 20:00:00') 
     AND ([TypeId] != 10) 
     AND ([UserId] = 29041)) AS tr 
INNER JOIN dbo.Users u ON tr.UserId = u.Id 
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id 
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId 
INNER JOIN dbo.Types t ON tr.TypeId = t.Id ) AS t), 
CTE2 as (
SELECT tr.Id, 
     tr.Amount, 
     tr.TypeId, 
     t.Name AS [Type], 
     tr.Date, 
     tr.ExternalKey, 
     tr.ExternalDescription, 
     tr.GameId, 
     tr.GameProviderId, 
     gp.Name AS GameProvider, 
     u.Username, 
     u.Pincode, 
     gp.Name, 
     g.GameName, 
     u.OperatorId, 
     tr.BalanceBefore, 
     tr.BalanceAfter, 
     tr.UserId 

FROM (SELECT * 
     FROM dbo.TransactionHistory th --WITH(INDEX(IX_TransactionHistory_DateType_UserId)) 
     WHERE (1 = 1) 
     AND ([Date] >= '2017-07-17 20:00:00') 
     AND ([TypeId] != 10) 
     AND ([UserId] = 29041) as tr 
INNER JOIN dbo.Users u ON tr.UserId = u.Id 
LEFT JOIN dbo.GameProviders gp ON tr.GameProviderId = gp.Id 
LEFT JOIN dbo.Games g ON tr.GameId = g.GameId AND tr.GameProviderId = g.ProviderId 
INNER JOIN dbo.Types t ON tr.TypeId = t.Id) AS t 
) 
SELECT * from CTE1 
UNION ALL 
SELECT * from CTE2 
ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;