如何正确索引具有 2500 万行的 SQL Server 表

Posted

技术标签:

【中文标题】如何正确索引具有 2500 万行的 SQL Server 表【英文标题】:How to properly index SQL Server table with 25 million rows 【发布时间】:2019-03-07 00:10:29 【问题描述】:

我在 SQL Server 2008 R2 中创建了如下表:

CREATE TABLE [dbo].[7And11SidedDiceGame]
(
    [Dice11Sides] [INT] NULL,
    [Dice7Sides] [INT] NULL,
    [WhoWon] [INT] NULL
)

我添加了以下索引:

CREATE NONCLUSTERED INDEX [idxWhoWon] 
ON [dbo].[7And11SidedDiceGame] ([WhoWon] ASC)

然后我创建了一个 WHILE 循环来插入 2500 万个随机生成的行来统计结果以进行统计分析。

一旦我优化了插入函数(在循环之前和之后使用 BEGIN TRAN 和 COMMIT TRAN),While 循环运行良好。但是,分析数据需要很长时间。例如:使用以下语句大约需要 4 分钟来执行:

DECLARE @TotalRows real

SELECT @TotalRows = COUNT(*) 
FROM [test].[dbo].[7And11SidedDiceGame]

PRINT REPLACE(CONVERT(VARCHAR, CAST(@TotalRows AS money), 1),'.00','') 

SELECT 
    WhoWon, COUNT(WhoWon) AS Total,  
    ((COUNT(WhoWon) * 100) / @TotalRows) AS PercentWinner
FROM 
    [test].[dbo].[7And11SidedDiceGame]
GROUP BY 
    WhoWon

我的问题是如何更好地索引表以加快数据检索?还是我需要以不同的方式提取数据?

【问题讨论】:

【参考方案1】:

我不认为你可以在这里做很多事情。

查询必须从索引中读取所有 25M 行来计算它们。不过,25M 行并不算多,我希望在现代硬件上花费不到 4 分钟。 只需读取 100MB 的数据(好吧,实际上它更多,比如 200MB,但从磁盘上读取 200MB 应该不会需要 4 分钟)。

服务器是否负载过重?这张表有很多插入吗?

您可以通过在表中将WhoWon 列定义为NOT NULL 来进行小幅改进。你真的有 NULL 值吗?

然后在查询中使用COUNT(*) 而不是count(WhoWon)

如果此查询经常运行,但表中的数据不会经常更改,您可以创建一个索引视图,该视图实质上会具体化/缓存/预计算这些计数,因此将运行此类视图的查询会快得多。

【讨论】:

在尝试了其他一些建议后,将 WhoWon 更改为 NOT NULL 是最大的性能提升。在将列更改为 NOT NULL 之前,我仍然只有 3 分钟多一点。现在,修改列后,我在 3 秒。谢谢!!【参考方案2】:

您可以通过使用窗口函数来加快速度:

SELECT WhoWon, count(*) AS Total,   
       count(*) * 100.0 / sum(count(*)) over ()  as PercentWinner
FROM [test].[dbo].[7And11SidedDiceGame]
GROUP BY WhoWon;

这不提供单独的print 语句。

为了提高性能,请尝试在(WhoWon) 上建立索引。

【讨论】:

我已经在(WhoWon) 上有一个索引,如下CREATE NONCLUSTERED INDEX [idxWhoWon] ON [dbo].[7And11SidedDiceGame] ([WhoWon] ASC) 这个SELECT 语句比我的要快得多。在没有任何其他修改的情况下,这快了 25%。在将WhoWon 更改为NOT NULL(根据 Vladimir Baranov)之后,您的 select 语句仍然快了 25%。谢谢!

以上是关于如何正确索引具有 2500 万行的 SQL Server 表的主要内容,如果未能解决你的问题,请参考以下文章

具有 10+ 百万行的 MySQL 表 - 如何使用索引加快搜索速度?

如何在 SQL Server 中更新具有数百万行的大表?

MySQL:具有 100+ 百万行的索引表

当 SQL Server 表中的列“createdDate”从现在起经过 90 天后,如何更新其具有数百万行的列?我们可以使用触发器吗?

sql 10多万行的数据 求助

假如有一个2500 万行的开源项目,你敢动么?