索引以降低SORT的成本

时间:2014-02-02 10:03:50

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

我有这张桌子:

TopScores

Username char(255)
Score int
DateAdded datetime2

会有很多行。

我针对它运行以下查询(存储过程的代码)以获得前5名高分,并且特定用户名的分数前面是位于他们正上方的人和下面的人:

WITH Rankings
     AS (SELECT Row_Number() OVER (ORDER BY Score DESC, DateAdded DESC) AS Pos,
                --if score same, latest date higher
                Username,
                Score
         FROM   TopScores) 
SELECT TOP 5 Pos,
             Username,
             Score
FROM   Rankings
UNION ALL
SELECT Pos,
       Username,
       Score
FROM   Rankings
WHERE  Pos BETWEEN (SELECT Pos
                    FROM   Rankings
                    WHERE  Username = @User) - 1 AND (SELECT Pos
                                                      FROM   Rankings
                                                      WHERE  Username = @User) + 1 

我必须索引表,所以我首先添加了clustered:ci_TopScores(用户名)和非聚集:nci_TopScores(Dateadded,Score)。

查询计划显示群集完全被忽略(在我创建非聚集的I测试之前,它被查询使用),逻辑读取更多(与没有任何索引的表扫描相比)。

排序是成本最高的运营商。所以我将索引调整为聚集:ci_TopScores(Score desc,Dateadded desc)和nonclustered:nci_TopScores(Username)。

仍然排序成本相同。非聚集:nci_TopScores(用户名)再次被完全忽略。

如何有效避免对此表进行排序和索引的高成本?

1 个答案:

答案 0 :(得分:0)

CTE不使用用户名,所以不要惊讶它不使用该索引。

CTE只是语法。您正在评估CTE 4次。

尝试#temp,只评估一次。
但你需要考虑指数 我会跳过RowNumber并在#temp上放一个iden pk作为pos
我会跳过#temp

上的任何其他索引

对于TopScores,Score desc,DateAdded desc,Username asc的索引将有助于 但如果它是支离破碎的话,它将无济于事 这是一个在插入

时会分段的索引
insert into #temp (Score, DateAdded, Username)   
select Score, DateAdded, Username
 from TopScores
order by Score desc, DateAdded desc, Username asc  

select top 5 * 
  from #temp 
 order by pos 
union 
select three.* 
from #temp 
join #temp as three
  on #temp.UserName = @user 
 and abs(three.pos - #temp.pos) <= 1

那么如果在#temp UserName上有表扫描怎么办呢 只要创建一个索引,一次扫描就不需要了 无论如何,该指数将严重分裂。