OVER(ORDER BY Col)生成“排序”操作

时间:2013-10-30 13:14:10

标签: sql-server sql-server-2008 indexing query-optimization

我正在处理一个需要根据用户输入进行过滤,排序和分页的查询。现在我正在测试一个非常慢的案例,在检查查询计划时,“排序”占96%的时间。

数据模型真的不那么复杂,以下查询应该足够清楚,以了解发生了什么:

WITH OrderedRecords AS (
    SELECT 
        A.Id
        , A.col2
        , ...
        , B.Id
        , B.col1 
        , ROW_NUMBER() OVER (ORDER BY B.col1 ASC) AS RowNumber
    FROM A
    LEFT JOIN B ON (B.SomeThing IS NULL) AND (A.BId = B.Id)
    WHERE (A.col2 IN (...)) AND (B.Id IN (...))
)
SELECT
    *
FROM OrderedRecords WHERE RowNumber Between x AND y

A是一个包含大约100k记录的表,但在该字段中将增长到数千万,而B是具有5个项目的类别类型表(并且这将永远不会增长任何更大,然后可能更多)。 A.Id和B.Id上有聚簇索引。

性能非常糟糕,我想知道是否有可能以某种方式解决这个问题。例如,如果订单是A.Id而不是B.col1,那么一切都非常快。也许我可以优化B.col1是某种索引。

我已经尝试在字段本身上添加索引,但这没有帮助。可能是因为表B中不同项目的数量非常小(本身与A相比)。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

我认为这可能是问题的一部分:

   LEFT JOIN B ON (B.SomeThing IS NULL) AND (A.Id = B.Id)
    WHERE (A.col2 IN (...)) AND (B.Id IN (...)

你的LEFT JOIN逻辑上就像INNER JOIN一样,因为你有WHERE子句,因为只返回某些B.ID行。如果这是你的意图,那么继续使用内连接,这可能有助于优化器意识到你正在寻找有限数量的行。

答案 1 :(得分:0)

我建议你尝试一下。

对于B表创建索引:

create index IX_B_1 on B (col1, Id, SomeThing)

对于A表创建索引:

create index IX_A_1 on A (col2, BId) include (Id, ...)

include中填写表A的所有其他列,SELECT CTE中列出的所有列。

但是,如您所见,索引OrderedRecords是占用空间的,并且可以获取关于表数据本身的大小。

因此,作为替代方案,您可以尝试从索引的IX_A_1部分省略额外的列:

include

但在这种情况下,您将需要略微修改您的查询:

create index IX_A_2 on A (col2, BId) include (Id)