允许 null 的 ORDER BY 列很慢。为啥?
Posted
技术标签:
【中文标题】允许 null 的 ORDER BY 列很慢。为啥?【英文标题】:ORDER BY column that has allow null is slow. Why?允许 null 的 ORDER BY 列很慢。为什么? 【发布时间】:2011-04-20 21:22:19 【问题描述】:所以真的我的问题是为什么这有效。
无论如何,我有这个查询,它执行了一些内部连接,有一个 where 子句并在 nvarchar 列上执行 order by。如果我在没有 order by 的情况下运行查询,则查询时间不到一秒。如果我运行 WITH order by 查询,则需要 12 秒。
现在我有了一个好主意,将所有 INNER JOIN 更改为 LEFT JOIN。并且还包括 ORDER BY 子句。那只用了不到一秒钟。所以我想起了 LEFT JOIN 和 INNER JOIN 之间的区别。 INNER JOIN 检查 NULL 而 LEFT JOIN 不检查。所以我进入表格设计并取消选中“允许空值”。现在我运行 WITH INNER JOINs 和 ORDER BY 子句的查询,查询时间不到一秒。 为什么?
据我了解,FROM、JOINS、WHERE 和 SELECT 子句应该先运行并返回结果集。然后 ORDER BY 子句在结果记录集的最后运行。因此,查询应该花费 AT MOST 一秒钟,是的,即使该列允许空值。那么,为什么在没有 order by 子句的情况下查询需要不到一秒的时间,而在 WITH order by 子句中需要 12 秒呢?这对我来说没有意义。
以下查询:
SELECT PlanInfo.PlanId, PlanName, COALESCE(tResponsible, '') AS tResponsible, Processor, CustName, TaskCategoryId, MapId, tEnd,
CASE MapId WHEN 9 THEN 1 ELSE 2 END AS sor
FROM PlanInfo INNER JOIN [orders].dbo.BaanOrders_Ext ON PlanInfo.PlanName = [orders].dbo.BaanOrders_Ext.OrderNo
INNER JOIN [orders].dbo.BaanOrders ON PlanInfo.PlanName = [orders].dbo.BaanOrders.OrderNo
INNER JOIN Tasks ON PlanInfo.PlanId = Tasks.PlanId
INNER JOIN EngSchedToTimingMap ON Tasks.CatId = EngSchedToTimingMap.TaskCategoryId
WHERE (MapId = 9 OR MapId = 11 or MapId = 13 or MapId = 15)
AND([orders].dbo.BaanOrders_Ext.Processor = 'metest' OR tResponsible = 'metest')
ORDER BY PlanInfo.PlanId
【问题讨论】:
更改表架构将导致重新编译计划。您可以通过返回并允许 Null 来重现该问题,还是它不再可重现?如果它是可复制的,请发布两个计划。 记录数在哪里,执行计划在哪里,索引在哪里? 我认为这不是空值的问题。它完全取决于表的大小(表中的记录数)。 Order By 对结果中的所有记录进行排序。 您确定您在一秒钟内获得了所有条记录吗?无需订购,它可以非常快速地交付第一批记录。我确实犯了这个错误...... 此数据库中没有索引。查询结果为 5 条记录。我还是新手,所以我以前从未做过执行计划。 【参考方案1】:我不得不猜测这是由于在您正在排序的 PlanInfo.PlanId 上有一个索引。
SQL Server 可以简化集合,使其遵循索引并按照该顺序构建其余列。当字段为NULLable时,索引不能用于排序,因为它不会包含NULL值,而NULL值是偶然出现的,所以它决定沿着不同的路径进行优化。
显示执行计划总是有帮助的。要么粘贴计划的图像,要么只显示文本模式计划,即在查询上方添加一行,然后执行它
SET SHOWPLAN_TEXT ON;
<the query>
【讨论】:
【参考方案2】:当您使用 ORDER BY 子句时,您会强制数据库引擎对结果进行排序。这需要一些时间(特别是如果结果包含许多行) - 因此运行 1 秒而没有 ORDER BY 子句的查询可能会运行 12 秒。请注意,排序最多需要 O(N*log(N)) 时间,其中 N 是行数。
NULL 通常很慢的原因是它们必须被特殊对待。使用 NULL 排序会增加更复杂的比较条件并减慢排序速度。
【讨论】:
【参考方案3】:如果您的问题是“为什么 ORDER BY 子句会导致我的查询运行时间更长?”答案是因为排序结果被添加到查询执行计划中。
如果您使用 SQL Server Studio 中的“显示估计的查询执行计划”工具,它会准确地向您显示它认为 SQL Server 引擎会做什么。
【讨论】:
我将这个问题读作“为什么在列定义中禁止 NULLS 会加快查询速度?”编辑:虽然实际上有两个问题。一个人问为什么改变可空性有效,另一个人问“那么为什么在没有 order by 子句的情况下查询需要不到一秒的时间,但需要 12 秒 WITH order by 子句?”以上是关于允许 null 的 ORDER BY 列很慢。为啥?的主要内容,如果未能解决你的问题,请参考以下文章