SQL Server UNION ALL合并连接(连接)太慢

时间:2017-08-17 15:56:59

标签: sql-server tsql union-all

我有一个select查询,它在两个具有相同结构的表上使用UNION ALL关键字(列和主键,它们具有不同的非聚簇索引)。这两个表包含3900万行,其中一百万行,另一行3800万行。仅在具有一百万行的table1上运行查询时,大约需要0.2秒,在table2上我们有不同的情况,最多需要0.5到1.2秒,具体取决于DB的压力。

实际上,为了显示我需要将这两个表联合起来,但问题是联合查询需要花费8秒才能运行。在查看执行计划时,最繁重的操作是Merge Join (Concatenation),成本为91%,我有点担心,因为我正在运行的WHERE子句从{{1}中选择了51个条目来自table1的0个条目(较大的表格)。

我无法理解它,我过去两天一直试图找到问题的解决方案,我找到的只是table2而不是UNION或不必要的条款,如UNION ALLGROUP BY。查询也进行分页,使用此命令LEFT/INNER JOINS,所有测试(在单个表上并使用ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;)都是使用分页(UNION ALLOFFSET)关键字执行的。< / p>

如果需要,我可以提供表格详细信息和查询详细信息。它是一个带有2 FETCH NEXT和2 INNER JOINS的简单选择查询,所有连接表都包含非常少量的数据(范围从50个条目到20K条目)。

这是查询

LEFT JOINS

1 个答案:

答案 0 :(得分: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;