我们正在尝试优化一些查询。
一个查询正在执行以下操作:
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]
(我已经删除了复杂的子查询。除了解释为什么这个查询已经作为一个两阶段过程完成之外,我认为它不相关。)
我思考使用子查询将其合并为单个查询会更有效率:
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
这将为优化器提供更好的信息,以确定正在进行的操作并避免使用任何临时表。我认为它应该更快。
但事实证明它慢得多。 8秒,而不到5秒。
我无法理解为什么会出现这种情况,因为我对数据库的所有了解都意味着子查询总是比使用临时表更快。
我错过了什么?
修改 -
从我从查询计划中可以看到,两者在很大程度上是相同的,除了临时表有一个额外的“表插入”操作,成本为18%。
显然,由于它有两个查询,排序前N的成本在第二个查询中比在子查询方法中的排序成本高很多,因此很难直接比较成本。
我从计划中可以看到的一切都表明子查询方法会更快。
答案 0 :(得分:4)
“应该”对数据库性能来说是危险的。我经常发现临时表可以加快速度,有时甚至会非常快。简单的解释是,它使优化器更容易避免重复工作。
当然,我也看到临时表使事情变慢,有时慢得多。
没有什么可以替代分析和研究查询计划(尽管如此,阅读他们的估算)。
答案 1 :(得分:3)
显然,SQL Server正在选择错误的查询计划。是的,这可能发生,我和你几次完全一样。
问题是优化查询(你提到“复杂的子查询”)是一项非常重要的任务:如果你有n个表,那么大概有n个!可能的加入订单 - 这只是一个开始。所以,做(a)首先你的内部查询和(b)然后你的外部查询是一个好方法,这是非常合理的,但SQL Server不能在合理的时间内推断出这些信息。
您可以做的是帮助 SQL Server。正如Dan Tow在他的伟大着作“SQL Tuning”中所写,关键通常是连接顺序,从最具选择性的表到最不具有选择性的表。使用常识(或他的书中描述的方法,这要好得多),您可以确定哪个连接顺序最合适,然后使用FORCE ORDER
查询提示。
无论如何,每个查询都是唯一的,没有“魔术按钮”可以让SQL Server更快。如果您真的想知道发生了什么,您需要查看(或向我们展示)查询的查询计划。其他有趣的数据由SET STATISTICS IO显示,它将告诉您查询产生多少(昂贵的)HDD访问。
答案 2 :(得分:0)
我在这里重复了这个问题:How can I force a subquery to perform as well as a #temp table?
它的结论是,是的,我得知有时候,优化者干涉你的子查询是正确的,好像它们不是完全自包含但有时候当它试图在某种程度上变得聪明时会出现错误的错误我们都熟悉。我说必须有一种方法可以在必要时关闭“聪明”,而不是用临时表来破坏View引导的方法。