23

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

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

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

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

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

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

我怎样才能强制 SQL Server 到SORT just before 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有几千条记录,而mytable在同一个MSSQL实例中的其他数据库有几百万条记录。两个表在各自的列上都有索引。sortcode

4

1 回答 1

12

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

您可以尝试将过滤部分放入子查询或 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/查询该 UDF ORDER BY,那么您已经很好地强制了查询顺序(因为 SQL Server 目前无法围绕多语句 UDF 进行优化)。


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

于 2011-06-09T14:17:26.647 回答