我正在使用此查询从 Sql Server 数据库中获取用户的排名:
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 - Unique, NONCLUSTERED INDEX
score - Non-unique, NONCLUSTERED INDEX
如果我更改查询并使用 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 parse and compile time: CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms.
(1 row(s) affected) Table 'users_stats'. Scan count 1, logical reads 22529, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times: CPU time = 78 ms, elapsed time = 3576 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
最佳答案
我怀疑你性能下降的主要原因是你的索引没有覆盖。通过进行索引覆盖,您可能会看到性能的显着提高。 Here是一篇讨论覆盖索引的好文章。
简而言之,索引只是提供指向行的指针。为了获得对结果集进行排名所需的“score”列的数据,引擎必须扫描聚簇索引以查找数据。如果将值包含在索引中,引擎将能够执行操作而无需聚集索引扫描。
索引应该改写如下:
CREATE UNIQUE NONCLUSTERED INDEX UQ_USER_STATS_USER_ID ON user_stats (user_id) INCLUDE (score);
关于sql - 优化排名查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28699142/