无论ORDER BY如何,SELECT TOP都很慢

ric*_*ent 22 t-sql sql-server sql-server-2005 query-hints sql-execution-plan

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

SELECT *
   FROM myview, foo, bar 
   WHERE shared=1 AND [joins and other stuff]
   ORDER BY sortcode;
Run Code Online (Sandbox Code Playgroud)

如上所示的查询计划显示了Sort在决赛之前的操作SELECT,这正是我所期望的.只有35个匹配的记录,查询在2秒内完成.

但是,如果我添加TOP 30,查询需要将近3分钟!使用SET ROWCOUNT同样慢.

查看查询计划,它现在似乎在连接和过滤器myview 之前对所有200多万条记录进行排序.

这个"排序"在查询计划中显示为索引上的sortcode索引扫描,主表上的聚簇索引查找以及它们之间的嵌套循环,所有这些都在连接和过滤器之前.

如何SORT 在之前 强制SQL Server 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
Run Code Online (Sandbox Code Playgroud)

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

Dam*_*ver 10

所以开始了"试图超越优化器(因为它并不总是最了解)"的不幸游戏.

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

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

这可能足以迫使它首先过滤(但优化器在每个版本中都变得"更聪明",并且有时可以看到这样的恶作剧).或者您可能必须将此代码放入UDF中.如果您将UDF编写为多语句表值函数,并在其中进行过滤,然后使用TOP x/ 查询该UDF,则您ORDER BY很好地强制执行查询顺序(因为SQL Server当前无法针对多语句UDF 进行优化).


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

  • 优化器有时是相当愚蠢的比利:). (6认同)