クラスター化インデックスによって一意に決定される追加列の場合のインデックスのカバー
-
20-09-2019 - |
質問
次のように luTab から myTab を更新する必要があるとします。
update myTab
set LookupVale = (select LookupValue from luTab B
where B.idLookup = myTab.idLookup)
luTab は 2 つの列 (idLookup(unique)、LookupValue) で構成されます。
どちらが望ましいか:idLookup の一意のクラスター化インデックス、または idLookup と Lookupvalue を組み合わせたものですか?この状況でカバリングインデックスは何か違いを生むのでしょうか?
(私は主に SQL サーバーに興味があります)
エピローグ:
myTab で 2,700 万行、luTab で 150 万行を使用して、以下の Krips テストを追跡しました。重要な部分はインデックスの一意性であるようです。インデックスが一意に指定されている場合、更新ではハッシュ テーブルが使用されます。一意として指定されていない場合、更新ではまず idLookup (ストリーム集約) によって luTab が集約され、次にネストされたループが使用されます。これははるかに遅いです。拡張インデックスを使用すると、SQL はその LookupValue が一意であるとはみなされなくなり、より低速なストリーム集合体でネストされたループ ルートが強制的に実行されます。
解決
私はあなたのテーブルを作成し、わずか数記録(50かそこらのルックアップ、およびMyタブ15)をロードしました。
それから私は、さまざまなインデックスのオプションを試してみました。 luTabにシークインデックスは常に29%のコストを持っています。
ストリーム集計およびアサートを:興味深いビットは、あなたがluTab上のインデックスにLookupValue列に追加した場合、インデックスがシーク後に実行計画は、2つの余分なステップを示しているということです。コストは0%ですが、それはより多くのデータに上がることがあります。
私はまた、「含まれて列」としてLookupValue含むだけidLookupに非クラスタ化インデックスを試してみました、としました。その方法は、データページは、その列ことを検索するためにアクセスする必要はありません。実行計画が異なる何も表示されません(ただし、彼らはどちらかのストリーム集計/アサートを持っていない)が、それはあなたのための選択肢かもしれません。
-Krip
他のヒント
まず:
- カバリングインデックスは常に非クラスター化されます。
- PK とクラスター化インデックスは常に必要です (SQL Server にはデフォルトで同じものがあります)。
2つの概念は別のものです
それで:
- これが行を一意に識別する場合、PK (クラスター化) は idLookup になります。
- カバーするインデックスは (idLookup) INCLUDE (LookupValue) になります。
しかし:
- idLookup は PK (クラスター化) であるため、カバー インデックスは必要ありません
- クラスター化インデックス (PK) は、クラスター化インデックスの性質により暗黙的に「カバー」されます (単純に、インデックスは最下位レベルのデータです)。