我正在使用此查询从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。
答案 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';