【问题标题】:SELECT TOP is slow, regardless of ORDER BYSELECT TOP 很慢,不管 ORDER BY
【发布时间】:2011-09-11 07:47:57
【问题描述】:

我在 SQL Server 中针对视图运行了一个相当复杂的查询,格式如下:

SELECT *
   FROM myview, foo, bar 
   WHERE shared=1 AND [joins and other stuff]
   ORDER BY sortcode;

如上所示的查询计划在最终的SELECT 之前显示了Sort 操作,这是我所期望的。只有 35 条匹配记录,查询时间不到 2 秒。

但是如果我添加TOP 30,查询大约需要3分钟!使用SET ROWCOUNT 一样慢。

查看查询计划,它现在似乎对myview 中的所有 2+ 百万条记录进行了排序在连接和过滤器之前

这种“排序”在查询计划中显示为对sortcode 索引的索引扫描、主表上的聚集索引搜索以及它们之间的嵌套循环,所有这些都在连接和过滤器之前。

如何强制 SQL Server 使用 SORT 就在 TOP 之前,就像未指定 TOP 时一样?

我认为myview 的构造不是问题,但以防万一,它是这样的:

CREATE VIEW myview AS
   SELECT columns..., sortcode, 0 as shared FROM mytable
   UNION ALL
   SELECT columns..., sortcode, 1 as shared FROM [anotherdb].dbo.mytable

本地mytable有几千条记录,而同一个MSSQL实例中另一个数据库中的mytable有几百万条记录。两个表在各自的sortcode 列上都有索引

【问题讨论】:

  • 那么,您查询中的WHERE shared=1 实际上取消了UNION 视图的第一部分?
  • @ypercube,是的,在这个特定查询的情况下。
  • 如果您发布查询的整个[joins and other stuff] 部分不会有什么坏处。也许缺少其他一些索引是导致优化器走慢路的原因。

标签: sql-server sql-server-2005 tsql sql-execution-plan query-hints


【解决方案1】:

因此开始了“试图智取优化器(因为它并不总是最了解)”的不幸游戏。

您可以尝试将过滤部分放入子查询或 CTE:

SELECT TOP 30 *
FROM
   (SELECT *
   FROM myview, foo, bar 
   WHERE shared=1 AND [joins and other stuff]) t
ORDER BY sortcode;

这可能足以迫使它首先过滤(但优化器在每次发布时都会变得“更聪明”,并且有时可以看穿这些恶作剧)。或者您可能不得不将此代码放入UDF。如果您将 UDF 编写为多语句表值函数,并在内部进行过滤,然后使用您的 TOP x/ORDER BY 查询该 UDF,那么您已经很好地强制了查询顺序(因为 SQL Server 目前无法围绕多语句 UDF 进行优化)。


当然,考虑一下,引入 UDF 只是一种隐藏我们真正在做的事情的方式 - 创建一个临时表,使用一个查询来填充它(基于 WHERE 过滤器),然后另一个查询来查找TOP x 来自临时表。

【讨论】:

  • 提示:一定要包含ORDER BY,否则这个技巧将不起作用!
猜你喜欢
  • 2016-10-23
  • 2023-02-01
  • 1970-01-01
  • 2011-02-22
  • 2017-05-09
  • 2017-07-13
  • 2020-11-28
  • 1970-01-01
  • 2013-02-21
相关资源
最近更新 更多