优化SQL Server排名索引

iLo*_*och 4 database optimization performance ranking sql-server-2014

我们有一个广泛的表,我们目前正在尝试优化.该表有50列(统计数据),我们最终希望按降序排列.目前有超过500万行.

我们正在寻找在降低复杂性和提高读取速度方面优化此表的方法.写入速度对我们来说也很重要,但读取更为关键.这些统计数据的排名应该尽可能接近实时,最佳解决方案是在每个请求的基础上快速排名(新行一直在增加,我们希望尽快显示这些行的排名) .)

我们目前正在评估垂直表格布局是否会更好.)更容易使用.

因为插入的统计数据不一定定义得很好,所以如果它们没有硬编码到表中,则更容易(因此优先选择垂直表结构.)

以下是我们当前的表结构和查询:

CREATE TABLE Stats 
(
    Id BIGINT PRIMARY KEY NOT NULL,
    UserId INT,
    Name VARCHAR(32) NOT NULL,
    Value DECIMAL(10,4) DEFAULT ((0)) NOT NULL,
    UpdatedAt DATETIME
);

CREATE INDEX Leaderboard__index ON Stats (Name, Value DESC);

SELECT
    Id,
    Name,
    Value,
    RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank
FROM 
    Stats
ORDER BY 
    Value DESC
Run Code Online (Sandbox Code Playgroud)

通常我们要么搜索任何给定统计数据的前N行(如排行榜),要么我们选择单个UserId并获得与该UserId相关的所有统计数据的排名.

数据相当大(正如我上面提到的,因为有很多行和很多列,垂直表结构可能在2.5亿行的范围内并且将继续增长.)

我们希望在需要的任何硬件上尽快获取这些数据,秒是我们的目标,因为我们目前在分钟范围内.

在对垂直表结构的测试中,我们插入了超过400,000行的数据,上面的查询需要不到3分钟(尽管它也只需要大约18秒来排名10,000行.)

我很乐意听到任何建议.谢谢你的时间!

The*_*war 9

你拥有的索引对你的窗口函数没用,因为

1.为了获得ID列值,SQL可能最终进行密钥查找,甚至最终扫描整个其他索引(如果它已经过了)Tipping point.因此,您的索引可能根本不被使用.

你是通过val desc订购的,它需要一个没有合适索引的排序,甚至可能最终溢出到TEMPDB

3.对于一个有趣的碎片方面,见下文

通常,为了使Window函数表现良好,您需要一个POC索引来表示

P,O - 按列分区和排序应在关键子句
C中 - 覆盖 - 应包括在select中包含的列

因此,以下查询以最佳方式工作.

SELECT
    Id,
    Name,
    Value,
    RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank
FROM 
    Stats
ORDER BY 
    Value DESC
Run Code Online (Sandbox Code Playgroud)

您将需要以下索引

create index nci_test on dbo.table(name,value desc)
include(id)
Run Code Online (Sandbox Code Playgroud)

使用" value desc" 创建的索引还有一个问题.

通常在索引中,默认情况下所有值都将以升序顺序存储,但是使用此索引时,您要求以相反的方式存储,这可能会导致逻辑碎片,这可以从Martin Smith的答案中看出.从中删除相关的术语回答这里......

如果使用降序键创建索引但新行附加了升序键值,那么您最终可能会出现逻辑顺序中的每个页面.扫描表时,这会严重影响IO读取的大小,并且不在缓存中

这么少的选择..

1.根据您的频率运行索引重建,看它是否有帮助

2.通过partition子句更改查询顺序将消除使用"val desc"选项创建索引的需要

SELECT
        Id,
        Name,
        Value,
        RANK() OVER (PARTITION BY Name ORDER BY Value DESC) AS Rank
    FROM 
        Stats
    ORDER BY 
        name DESC
Run Code Online (Sandbox Code Playgroud)

上面的查询不需要像你创建的那样创建一个索引.你可以像下面那样改变它.它还处理上面提到的碎片方面

CREATE INDEX Leaderboard__index ON Stats (Name, Value)
include(id);
Run Code Online (Sandbox Code Playgroud)

参考:
使用窗口函数的Microsoft SQL Server 2012高性能T-SQL