如何确定创建索引的成本?

SEa*_*986 3 performance index sql-server sql-server-2014

我有一个表,我想在其上创建索引以提高SELECT使用该表的几个查询的性能。

如何测试索引是否对表上的 DUI 操作产生了任何显着的不利影响?

该表是日志表,因此经常写入。在创建所需索引之前和之后针对该表运行特定INSERTUPDATE查询是一种情况吗?

Jos*_*ell 10

如果您有一个非生产环境,您可以通过运行SQL Query Stress来模拟您的插入/更新工作负载。在添加索引以获得基线之前执行此操作,然后查看它的速度有多慢,以及该更改是否可以接受。

除了 DUI 操作的额外开销之外,另一个考虑因素是阻塞. 您的阻塞模式可能与您习惯的不同,因为某些SELECT查询将使用新索引,并且插入/更新必须锁定该索引聚集索引。

我指出这一点只是为了说明酒后驾车“开销”不是唯一的考虑因素。添加索引通常有助于阻塞,因为对较窄 NC 索引的 SELECT 查询不会被聚集索引中其他列的更新阻塞。


在不了解您的表的情况下,这里是 SQL Query Stress 方法可能是什么样子的快速演练。我将在新数据库中设置一个“LogTable”:

USE [master];
GO

CREATE DATABASE [232113];
GO

ALTER DATABASE [232113] SET RECOVERY SIMPLE WITH NO_WAIT;
GO

USE [232113];
GO

CREATE TABLE dbo.LogTable
(
    Id INT PRIMARY KEY IDENTITY(1,1),
    Col1 DATETIME NOT NULL,
    Col2 CHAR(4) NOT NULL
);
Run Code Online (Sandbox Code Playgroud)

然后我使用这两个查询来模拟 INSERT/UPDATE 工作负载:

-- insert a row
INSERT INTO dbo.LogTable
    (Col1, Col2)
VALUES
    (GETDATE(), 'val2');

-- update a random row
UPDATE dbo.LogTable
SET Col2 = 'val3'
WHERE Id = (SELECT TOP (1) Id 
            FROM dbo.LogTable 
            ORDER BY NEWID());
Run Code Online (Sandbox Code Playgroud)

然后我在 6 个线程上运行 SQL Query Stress,每个线程 250 次迭代,每次执行之间有 100 毫秒的延迟。这在大约 25 秒内完成,只需要聚集索引就位。

SQL 查询压力结果截图

现在我将在 Col2 上创建一个非聚集索引,它受插入和更新的影响:

CREATE NONCLUSTERED INDEX IX_Col2 ON dbo.LogTable (Col2);
Run Code Online (Sandbox Code Playgroud)

再次运行测试,花费的时间基本相同(25 秒)。请注意,逻辑读取增加了,所以这里有一些成本(它只是不影响整体持续时间)。

SQL 查询压力结果截图

当然,这是一个非常简单的案例,“服务器”(我的笔记本电脑)上没有其他活动,因此差异很小。但希望它展示了这个概念。