非クラスター化インデックスがクラスター化インデックスのキーを使用して行を見つけるときと、そのテーブルにクラスター化インデックスがなく、非クラスター化インデックスがRIDを介して行を見つけるときのパフォーマンスに違いはありますか?
異なるレベルの断片化は、このパフォーマンスの比較にも影響しますか? (たとえば、両方のシナリオで、テーブルは0%断片化されているのに対し、50%対100%)。
断片化bogeyeman(シングルトンルックアップを実行する場合は実際には問題ではありません)を除いて、主な違いは、RIDが行があるページを正確に指定するのに対し、キールックアップでは、クラスター化インデックスの非リーフレベルをトラバースします。ターゲットページを検索します。 Aaron Bertrandはこれについていくつかのテストを行いました RIDルックアップはキールックアップよりも高速ですか?
ただし、ヒープには 転送されたフェッチ(またはレコード) を含めることができます。その場合、ターゲット行を見つけるために複数の論理IOが必要です。
私は これについて最近ブログに書いた であり、コメントの回答を避けるために、ここでコンテンツを複製しています。
CREATE TABLE el_heapo
(
id INT IDENTITY,
date_fudge DATE,
stuffing VARCHAR(3000)
);
INSERT dbo.el_heapo WITH (TABLOCKX)
( date_fudge, stuffing )
SELECT DATEADD(HOUR, x.n, GETDATE()), REPLICATE('a', 1000)
FROM (
SELECT TOP (1000 * 1000)
ROW_NUMBER() OVER (ORDER BY @@SPID)
FROM sys.messages AS m
CROSS JOIN sys.messages AS m2
) AS x (n)
CREATE NONCLUSTERED INDEX ix_heapo ON dbo.el_heapo (date_fudge);
sp_BlitzIndex でテーブルを見ることができます
EXEC master.dbo.sp_BlitzIndex @DatabaseName = N'Crap',
@SchemaName = 'dbo',
@TableName = 'el_heapo';
このクエリはブックマークルックアップを生成します。
SELECT *
FROM dbo.el_heapo AS eh
WHERE eh.date_fudge BETWEEN '2018-09-01' AND '2019-09-01'
AND 1 = (SELECT 1)
OPTION(MAXDOP 1);
これで、転送されたレコードを発生させることができます。
UPDATE eh
SET eh.stuffing = REPLICATE('z', 3000)
FROM dbo.el_heapo AS eh
WHERE eh.date_fudge BETWEEN '2018-09-01' AND '2019-09-01'
OPTION(MAXDOP 1)
BlitzIndexはそれらを私たちに示します:
ルックアップクエリを再実行すると、次のようになります。
プロファイラーにも違いが表示されます:
クラスタ化インデックスの非リーフレベルのトラバース(基本的にはridルックアップのキーと異なるものです)はほとんどすべてメモリ内にあることを覚えておいてください。 SQL Serverはルート、次のレベルなどを何度も何度も読み取ります。つまり、それらは非常に高温になります。
これをヒープ内の転送されたレコードと比較してください。あなたはあなたが1つの行を見つけたと思います、しかし、dar、それはどこか別の場所です。あなたは、いわば、あちこち飛び跳ねます。したがって、ここで「読み取り」だけを見るように注意する必要があります。論理読み取りと物理読み取りが要因になります。
そしてもちろん、非常に重要な側面は、最初にヒープ転送レコードがある場合です。 Sys.dm_db_index_physical_statsにDetailedオプションを指定するとわかります。