我有一个查询,使用FULL JOIN需要2.5秒,使用INNER,RIGHT或LEFT JOIN需要40秒。
这是查询。子查询(完成两次)只需要1.3秒。
SELECT T1.[time], T1.Total, T1.rn, T2.[time], T2.Total, T2.rn
FROM
(
select [time], MAX(ComputedValue) as Total, row_number() over (order by [time]) as rn
FROM
(
select SUBSTRING(CONVERT(CHAR(10), IntervalStartTime, 108), 0, 6) as [time], ComputedValue
from LoadTestTransactionSample
where LoadTestRunId=285
and CounterName='Total Transactions'
and TransactionName='Export'
) foo
group by [time]
) T1
_____ JOIN
(
select [time], MAX(ComputedValue) as Total, row_number() over (order by [time]) as rn
FROM
(
select SUBSTRING(CONVERT(CHAR(10), IntervalStartTime, 108), 0, 6) as [time], ComputedValue
from LoadTestTransactionSample
where LoadTestRunId=285
and CounterName='Total Transactions'
and TransactionName='Export'
) foo
group by [time]
) T2
ON T1.rn = T2.rn - 1
select SUBSTRING
位只是从DateTime中获取HH:MM字符串。 LoadTestTransactionSample
实际上是一个连接8个表的VIEW。 (仅供参考,数据库是Visual Studio加载测试结果存储区)。以下是其(相关)专栏:
LoadTestRunId INT NOT NULL
CounterName NVARCHAR(255) NOT NULL
TransactionName NVARCHAR(64) NOT NULL
IntervalStartTime DATETIME NOT NULL
IntervalEndTime DATETIME NOT NULL
ComputedValue REAL
FULL JOIN会返回一个额外的不需要的行,所以我需要做一个正确的JOIN才能得到正确的答案。
我不是在寻找解决方案(我有一个:将子查询预取到表变量中使用SQL Server 2012分析函数'LAG',感谢@ a1ex07),只是对可能导致这些连接类型之间性能差异的原因的理解。
修改 这是slow right join query plan和fast full join query plan。它们太大了,无法发布截图。
编辑2: 实际上,查询计划的正确加入率为45%,加入加权值为55%,结果是完全不准确(实际上最终会低于99%/ 1%)。我想这意味着我必须依赖实际的执行统计数据。
编辑3: RIGHT JOIN的统计数据:
(40 row(s) affected)
Table 'LoadTestPerformanceCounterCategory'. Scan count 0, logical reads 37556, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounter'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestScenario'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestCase'. Scan count 0, logical reads 176464, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'WebLoadTestTransaction'. Scan count 0, logical reads 13411100, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounterInstance'. Scan count 0, logical reads 36563718, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounterSample'. Scan count 19721, logical reads 269657, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestRunInterval'. Scan count 41, logical reads 205, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 36754 ms, elapsed time = 36763 ms.
快速加入的统计数据:
(41 row(s) affected)
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounterCategory'. Scan count 0, logical reads 1832, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounter'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestScenario'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestCase'. Scan count 0, logical reads 8608, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'WebLoadTestTransaction'. Scan count 0, logical reads 654200, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounterInstance'. Scan count 0, logical reads 1783596, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestPerformanceCounterSample'. Scan count 962, logical reads 13154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'LoadTestRunInterval'. Scan count 2, logical reads 10, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 1950 ms, elapsed time = 1944 ms.
RIGHT JOIN正在进行比FULL JOIN更多的读取和更多扫描,尽管有一个明显相似的查询计划。
工作表(在FULL JOIN中)提示?这是临时表吗?
这似乎表明查询优化器已损坏吗?
答案 0 :(得分:2)
好的,事实证明答案是:糟糕的数据库统计数据。很坏。如在,从未更新。
exec sp_updatestats;
FTW。
[羞愧地隐藏]
答案 1 :(得分:1)
这是类似查询的执行计划。表非常小。
查询1 :
INNER JOIN
。查询2 :
FULL JOIN
。原因: 在我的案例中INNER JOIN正在使用HASH MATCH。而且FULL JOIN正在使用NESTED LOOP。这由SQL优化器决定必须使用哪个物理连接(但是我们可以使用其他物理连接)。检查你的执行计划,它会有所帮助。