ROW_NUMBER()查询计划排序优化

时间:2016-02-25 17:56:22

标签: sql sql-server indexing sql-execution-plan

下面的查询访问包含超过3000万行的Votes表。然后使用WHERE n = 1选择结果集。在查询计划中,ROW_NUMBER()窗口函数中的SORT操作是查询成本的95%,并且完成执行需要6分钟。

我已经在same_voter, eid, country include vid, nid, sid, vote, time_stamp, new上有一个索引来覆盖where子句。

最有效的方法是纠正这个问题,以便在vid, nid, sid, new DESC, time_stamp DESC上添加索引,或者是否可以使用ROW_NUMBER()函数以更有效的方式获得相同的结果?

SELECT v.vid, v.nid, v.sid, v.vote, v.time_stamp, v.new, v.eid,
    ROW_NUMBER() OVER (
        PARTITION BY v.vid, v.nid, v.sid ORDER BY v.new DESC, v.time_stamp DESC) AS n
FROM dbo.Votes v
WHERE v.same_voter <> 1
    AND v.eid <= @EId
    AND v.eid > (@EId - 5)
    AND v.country = @Country

1 个答案:

答案 0 :(得分:1)

使用ROW_NUMBER()的一种可能替代方法:

SELECT
    V.vid,
    V.nid,
    V.sid,
    V.vote,
    V.time_stamp,
    V.new,
    V.eid
FROM
    dbo.Votes V
LEFT OUTER JOIN dbo.Votes V2 ON
    V2.vid = V.vid AND
    V2.nid = V.nid AND
    V2.sid = V.sid AND
    V2.same_voter <> 1 AND
    V2.eid <= @EId AND
    V2.eid > (@EId - 5) AND
    V2.country = @Country AND
    (V2.new > V.new OR (V2.new = V.new AND V2.time_stamp > V.time_stamp))
WHERE
    V.same_voter <> 1 AND
    V.eid <= @EId AND
    V.eid > (@EId - 5) AND
    V.country = @Country AND
    V2.vid IS NULL

查询基本上表示要获取符合条件的所有行,然后加入到符合相同条件的任何其他行,但根据newtime_stamp对分区进行排名更高的行列。如果没有找到,那么这必须是您想要的行(它排名最高),如果找不到,则表示V2.vid将是NULL。我假设vid否则永远不会NULL。如果它是您表格中的NULL能列,那么您需要调整查询的最后一行。