我有一个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 ALL
或GROUP BY
。查询也进行分页,使用此命令LEFT/INNER JOINS
,所有测试(在单个表上并使用ORDER BY [Id] DESC OFFSET 0 ROWS FETCH NEXT 25 ROWS ONLY;
)都是使用分页(UNION ALL
和OFFSET
)关键字执行的。< / p>
如果需要,我可以提供表格详细信息和查询详细信息。它是一个带有2 FETCH NEXT
和2 INNER JOINS
的简单选择查询,所有连接表都包含非常少量的数据(范围从50个条目到20K条目)。
这是查询
LEFT JOINS
答案 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;