web-dev-qa-db-ja.com

インデックス作成のコストを決定する方法は?

テーブルを使用するいくつかのSELECTクエリのパフォーマンスを向上させるためにインデックスを作成するテーブルがあります。

インデックスがテーブルのDUI操作に重大な悪影響を及ぼすかどうかをテストするにはどうすればよいですか?

テーブルはログテーブルであるため、頻繁に書き込まれます。目的のインデックスを作成する前後に、そのテーブルに対して特定のINSERTまたはUPDATEクエリを実行するケースですか?

3
SEarle1986

非本番環境を使用している場合は、 SQL Query Stress を実行して、挿入/更新ワークロードをシミュレートできます。インデックスを追加してベースラインを取得する前にそれを行ってから、それがどれほど遅いか、およびその変更が許容できるかどうかを確認してください。

DUI操作の追加のオーバーヘッドに加えて、別の考慮事項はblockingです。一部のSELECTクエリは新しいインデックスを使用し、挿入/更新はそのインデックスをロックする必要があるため、これまでとは異なるブロッキングパターンが発生する可能性があります andクラスタ化インデックス。

これは、DUIの「オーバーヘッド」だけが考慮事項ではないことを指摘するために指摘しています。より狭いNCインデックスに対するSELECTクエリはクラスター化インデックス内の他の列の更新によってブロックされないため、インデックスを追加すると、多くの場合helpがブロックされます。


テーブルについて何も知らずに、SQLクエリストレスアプローチがどのように見えるかを簡単に説明します。新しいデータベースに「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
);

次に、これら2つのクエリを使用して、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());

次に、SQLクエリストレスを6つのスレッドで実行し、スレッドごとに250回の反復を実行します。実行ごとに100ミリ秒の遅延があります。これは、クラスター化インデックスを配置しただけで約25秒で完了します。

screenshot of SQL Query Stress results

次に、挿入と更新の両方の影響を受けるCol2に非クラスター化インデックスを作成します。

CREATE NONCLUSTERED INDEX IX_Col2 ON dbo.LogTable (Col2);

テストを再度実行すると、基本的に同じ時間(25秒)かかりました。論理読み取りが増加したため、ここにはcostがいくつかあることに注意してください(全体の期間には影響しませんでした)。

screenshot of SQL Query Stress results

もちろん、これは非常に単純なケースであり、「サーバー」(私のラップトップ)で他のアクティビティがないため、違いはごくわずかです。しかし、うまくいけば、それは概念を実証します。

10
Josh Darnell