为什么使用临时表比嵌套查询更快?

Mon*_*ong 5 sql-server optimization query-optimization

我们正在尝试优化一些查询.

一个查询正在执行以下操作:

SELECT t.TaskID, t.Name as Task, '' as Tracker, t.ClientID, (<complex subquery>) Date,
INTO [#Gadget]
FROM task t

SELECT TOP 500 TaskID, Task, Tracker, ClientID, dbo.GetClientDisplayName(ClientID) as Client 
FROM [#Gadget]
order by CASE WHEN Date IS NULL THEN 1 ELSE 0 END , Date ASC

DROP TABLE [#Gadget]
Run Code Online (Sandbox Code Playgroud)

(我已经删除了复杂的子查询.除了解释为什么这个查询已经作为一个两阶段过程完成之外,我认为它不相关.)

认为使用子查询将其合并为单个查询会更有效率:

SELECT TOP 500 TaskID, Task, Tracker, ClientID, dbo.GetClientDisplayName(ClientID)
FROM
(
    SELECT t.TaskID, t.Name as Task, '' as Tracker, t.ClientID, (<complex subquery>) Date,
    FROM task t
) as sub    
order by CASE WHEN Date IS NULL THEN 1 ELSE 0 END , Date ASC
Run Code Online (Sandbox Code Playgroud)

这将为优化器提供更好的信息,以确定正在进行的操作并避免使用任何临时表.我以为它应该更快.

但事实证明它慢得多.8秒对比不到5秒.

我无法弄清楚为什么会出现这种情况,因为我对数据库的所有了解都意味着子查询总是比使用临时表更快.

我错过了什么?

编辑 -

从我从查询计划中可以看到的情况来看,两者在很大程度上是相同的,除了临时表具有额外的"表插入"操作,成本为18%.

显然,由于它有两个查询,排序前N的成本在第二个查询中比在子查询方法中的排序成本高得多,因此很难直接比较成本.

我从计划中看到的一切都表明子查询方法会更快.

Hei*_*nzi 3

显然,SQL Server 选择了错误的查询计划。是的,这可能会发生,我已经遇到过几次与你完全相同的情况。

问题是优化查询(您提到“复杂子查询”)是一项艰巨的任务:如果您有 n 个表,则大约有 n 个!可能的连接顺序——而这仅仅是开始。因此,(a) 首先执行内部查询,(b) 然后执行外部查询是一个不错的方法,但 SQL Server 无法在合理的时间内推断出此信息。

你能做的就是帮助SQL Server。正如 Dan Tow 在他的伟大著作《SQL Tuning》中所写,关键通常是连接顺序,从最具选择性的表到最不选择性的表。使用常识(或者他的书中描述的方法,这要好得多),您可以确定哪种连接顺序最合适,然后使用FORCE ORDER查询提示。

无论如何,每个查询都是唯一的,没有“神奇按钮”可以让 SQL Server 更快。如果您确实想了解发生了什么,您需要查看(或向我们展示)您的查询的查询计划。其他有趣的数据由SET STATISTICS IO显示,它将告诉您查询产生了多少(昂贵的)HDD 访问。