5

我有一个查询,使用 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 返回一个多余的不需要的行,所以我需要做一个 RIGHT JOIN 才能得到正确的答案。

我并不是真的在寻找解决方案(我有一个:使用 SQL Server 2012 分析函数“LAG”将子查询预取到表变量中,感谢@a1ex07),只是对可能导致极端差异的原因有所了解在这些连接类型之间的性能


编辑: 这是慢速右连接查询计划快速全连接查询计划。它们太大,无法发布屏幕截图。

编辑 2: 实际上查询计划的 RIGHT JOIN 为 45%,FULL JOIN 为 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.

快速 FULL JOIN 的统计信息:

(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 执行更多的读取和扫描。

Worktable (in FULL JOIN) 是一个提示吗?那是临时表吗?

这似乎表明查询优化器已损坏?

4

2 回答 2

2

好的,事实证明答案是:坏的数据库统计。很坏。如题,从未更新。

exec sp_updatestats;FTW。

[羞愧地捂住头]

于 2013-03-12T21:52:22.367 回答
1

这是类似查询的执行计划。桌子非常小。

执行计划

查询 1

  • 用途INNER JOIN.
  • 执行计划看起来更小。
  • 但是,占用了总时间的 62%。

查询 2

  • 用途FULL JOIN.
  • 执行计划看起来很大。
  • 但是,占用总时间的 38%。

原因:在我的情况下,INNER JOIN 使用的是 HASH MATCH。FULL JOIN 使用的是嵌套循环。这由 SQL 优化器决定必须使用哪个物理连接(但是我们可以为它使用其他物理连接)。检查你的执行计划,它会有所帮助。

于 2013-03-08T08:06:04.913 回答