优化排名查询

时间:2015-02-24 15:01:52

标签: sql sql-server

我正在使用此查询从Sql Server DB获取用户的排名:

select user_rank
from (select t.user_id, rank() over (order by score desc) as user_rank
  from user_stats t
 ) t
where t.user_id='some_user_id';

该表包含大约22,000行,查询需要3.5秒,这太慢了。

此表上有几个索引,这些是相关的:

  

user_id - 唯一的非垃圾索引

     

得分 - 非独特,非收集指数

如果我更改查询并使用id(这是我的主键)而不是user_id,那么查询会快速执行:

select user_rank
from (select t.id, rank() over (order by score desc) as user_rank
  from user_stats t
 ) t
where t.id='some_id';

检查执行计划后,我发现群集索引扫描成本是92%,但我不明白为什么在这种情况下需要它。

如何优化此查询?

查询的统计信息:

  

SQL Server解析和编译时间:CPU时间= 0 ms,经过时间=   0毫秒。

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 0毫秒。   SQL Server解析和编译时间:CPU时间= 0毫秒,已用时间=   0毫秒。

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 0毫秒。   SQL Server解析和编译时间:CPU时间= 0毫秒,已用时间=   0毫秒。

     

SQL Server执行时间:CPU时间= 0毫秒,已用时间= 0毫秒。   SQL Server解析和编译时间:CPU时间= 0毫秒,已用时间=   0毫秒。

     

(1行(s)受影响)表'users_stats'。扫描计数1,逻辑   读取22529,物理读取0,预读取读取0,lob逻辑读取   0,lob物理读取0,lob预读读取0。

     

(1行受影响)

     

SQL Server执行时间:CPU时间= 78毫秒,已用时间= 3576   女士。 SQL Server解析和编译时间:CPU时间= 0 ms,已过去   时间= 0毫秒。

     

SQL Server执行时间:CPU时间= 0 ms,已用时间= 0 ms。

2 个答案:

答案 0 :(得分:1)

我怀疑性能下降的主要原因是因为您的索引没有覆盖。通过使索引覆盖,您可能会看到性能的显着改善。 Here是一篇讨论覆盖索引的好文章。

简而言之,索引只提供指向行的指针。为了获得"得分的数据"如果要对结果集进行排名,则引擎必须扫描聚簇索引才能查找数据。如果在索引中包含该值,则引擎将能够执行操作而无需进行聚簇索引扫描。

索引应该按如下方式重写:

创建UNIQUE NONCLUSTERED INDEX UQ_USER_STATS_USER_ID ON user_stats(user_id)INCLUDE(得分);

答案 1 :(得分:0)

而不是

select user_rank
from (select t.id, rank() over (order by score desc) as user_rank
  from user_stats t
 ) t
where t.id='some_id';

怎么样

with t as (
  select t.user_id, 
  ROW_NUMBER() as user_rank
  from user_stats t
  order by score desc
)
select user_rank
from t
where t.id='some_id';