我在针对视图运行的SQL Server中有一个相当复杂的查询,格式为:
SELECT *
FROM myview, foo, bar
WHERE shared=1 AND [joins and other stuff]
ORDER BY sortcode;
如上所示的查询计划会在最终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
本地mytable
有几千条记录,同一MSSQL实例中另一个数据库中的mytable
有几百条记录。两个表在各自的sortcode
列上都有索引。
答案 0 :(得分:9)
因此开始了“试图超越优化器的不幸游戏(因为它并不总是最了解)”。
您可以尝试将过滤部分放入子查询或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
。