web-dev-qa-db-ja.com

列を含むインデックスと含まないインデックスの両方を持つ理由はありますか?

私は、過去数年間にわたって(多くのさまざまな開発者のもとで)重要な開発が行われているデータベースで、実行速度の遅いクエリをいくつか調べています。
最も一般的に使用されるテーブルの1つには、同じインデックス付きの列を持ついくつかのインデックスがありますが、1つには列が含まれ、もう1つには含まれません。

例えば:
1つのインデックス:

 CREATE NONCLUSTERED INDEX [IDX_tblTable_IndexedColumnId_Inc] ON [dbo].[tblTable]
 (
[IndexedColumnId] ASC
 )

そして他の:

CREATE NONCLUSTERED INDEX [IDX_tblTable_IndexedColumnId_Inc] ON [dbo].[tblTable]
(
[IndexedColumnId] ASC
)
INCLUDE (   [Field1Id],
[Field2],
[Field3],
[Field4],
[Field5],
[Field6]) 

これは単なる見落としであり、ディスクスペースと追加のオーバーヘッドを使い果たして、含まれる列なしでインデックスが作成されると考えられます(含まれる列は必要であることがわかっています)。

同じ列に2つのインデックスを作成するメリットはありますか。1つは含まれる列で、もう1つは含まれません。

7
Lithium

みんなの好きなn次元の類似物がコメントしたことを少し拡大するために、両方を持つことにはいくつかの利点があります

これは小さな(しかし不十分ではない)デモです。

必要なもの:

_USE StackOverflow;
SET NOCOUNT ON; 

CREATE TABLE dbo.IndexCrap
(
    Id INT IDENTITY PRIMARY KEY CLUSTERED,
    Whatever DATETIME,
    Nonsense VARCHAR(50),
    Etc UNIQUEIDENTIFIER,
    SoForth BIT
);

INSERT dbo.IndexCrap WITH (TABLOCK)
        (Whatever, Nonsense, Etc, SoForth )
SELECT TOP 1000 DATEADD(DAY, x.n, GETDATE()),
                REPLICATE('A', x.n % 50),
                NEWID(),
                CASE WHEN x.n % 15 = 0 THEN 1 ELSE 0 END
FROM (SELECT ROW_NUMBER() OVER (ORDER BY @@ROWCOUNT) AS n
        FROM sys.messages AS m ) AS x;
_

インデックス:

_CREATE INDEX ix_tinydancer ON dbo.IndexCrap (Whatever);

CREATE INDEX ix_largemarge ON dbo.IndexCrap (Whatever) INCLUDE (Nonsense, Etc, SoForth);
_

だからあなたの質問のように、1つの列のインデックスで、いくつかのインクルードを持つ同じ列の1つのインデックス。

クエリ:

_SELECT COUNT(*)
FROM dbo.IndexCrap AS ic;

SELECT ic.Nonsense, ic.Etc, ic.SoForth
FROM dbo.IndexCrap AS ic
WHERE ic.Whatever >= DATEADD(DAY, 500, GETDATE());
_

実行計画:

COUNT(*)クエリの場合、オプティマイザーはフィルターされていないため、より広い非クラスター化インデックスと少し広いクラスター化インデックスよりも小さい単一列インデックスを選択し、必要なのは行数だけです。

NUTS

より広いクエリの場合、オプティマイザーはカバーするインデックスを選択するため、a)クラスター化インデックスをスキャンしたり、b)より狭いインデックスにアクセスしてクラスター化インデックスにキールックアップを行ったりする必要はありません。

NUTS

もちろん、システムで実行されるすべてのクエリを知っているとは限りません。それが、私が勤務している会社が_sp_BlitzIndex_、 インデックスを分析するための無料のツール と書いている理由です。

_EXEC master.dbo.sp_BlitzIndex @DatabaseName = 'StackOverflow', @Mode = 4;_を実行すると、次のような結果が得られます。

NUTS

IndexCrapに追加した2つのインデックス(PK/CXは含まない)には、重複するキー列があるとしてフラグが付けられます。また、それらの定義、使用法、サイズ、およびスクリーンキャップに表示されていない多くの情報も提供します。

使用カウンターは完全ではありません。 SQL Serverの 一部のバージョン では、インデックスを追加または削除するとリセットされ、インデックスを再構築するとリセットされます。もちろん、SQL Serverを再起動するとリセットされます。

お役に立てれば!

8
Erik Darling