Grow up

生活とプログラミング

SQL Server 非クラスター化インデックスの動作と実行プランについて

はじめに

SQL Server の検索速度を上げる方法にインデックスの利用があります。
今回は「非クラスター化インデックス」についてまとめます。
学習に使用した資料は公式HPのSQL Server 2012 自習書シリーズになります。
SQL Server 2012 | マイクロソフト クラウド プラットフォーム

データベースは自習書シリーズに付属しているサンプルを使用しています。
詳細は以下の記事を参考にして下さい。
knkomko.hatenablog.com

クラスター化インデックスとは

ヒープ領域に保存されている実データへのポインタを持つインデックスです。
そのためインデックスを使用したSQLは以下のように動作します。
①インデックスを検索する Index Seek の動作
②検索したインデックスのポインタを辿って実データを読む RID Lookup の動作

f:id:knkomko:20200405192048p:plain:w450
引用 : インデックスの基礎とメンテナンス

実行プランの動作

実行プランの動作については以下のスライドが参考になりました。
④Clusted Index Scan、⑤Clusted Index Seek はクラスター化インデックスを使用した場合に行う為、非クラスター化インデックスでは使用されません。
f:id:knkomko:20200405220702p:plain:w350
引用 : https://www.slideshare.net/ssuser89be8d/index-tuning-129457451/12

インデックスを使用しない場合の実行プラン

最も遅い「Table Scan」を行っています。
f:id:knkomko:20200405222037p:plain:w350

インデックスを使用した場合の実行プラン

インデックスを姓列に作成します。
f:id:knkomko:20200405222416p:plain:w350

オブジェクトエクスプローラーから作成したインデックスが確認できます。
f:id:knkomko:20200405222512p:plain:w250

先ほどと同じSQLを実行すると高速な検索「Index Seek」を行っています。
f:id:knkomko:20200405222727p:plain:w350

インデックスを作成しても効果の無い列

1. WHERE句の検索条件にほとんど使用されない列
 インデックスを作成した列のデータを更新した際にインデックスのツリー構造も更新されるためパフォーマンスが低下する場合があります。

2. 検索条件に該当するデータが大量にある場合
 該当するデータが大量にあると RID Lookupによるデータの取得が、最も遅い「Table Scan」より効率が悪くなる場合があります。

検索結果に該当するデータが大量にある場合の実行プラン

LIKE文では295件のデータが該当し最も遅い「Table Scan」が行われました。
インデックスを使用していてもインデックスを利用しない検索が行われています。
f:id:knkomko:20200405230312p:plain:w350

"Aoki"で検索していた時は高速な検索「Index Seek」が行われていました。
f:id:knkomko:20200405222727p:plain:w350

インデックスが役立たない例

1. LIKE 演算子を利用する際に、先頭に % を指定している場合
 遅い検索「Index Scan」が行われています。
f:id:knkomko:20200405231538p:plain:w350

2. 演算子の左辺へ「関数」や「計算式」を記述している場合
 遅い検索「Index Scan」が行われています。
f:id:knkomko:20200405234844p:plain:w350

3. 列へ設定してある照合順序とは、異なる照合順序を指定している場合
 設定は「Japan_CI_AS」(大文字と小文字を区別しない)となっています。
f:id:knkomko:20200405234940p:plain:w350

 「Japan_CS_AS」を指定すると遅い検索「Index Scan」が行われています。
f:id:knkomko:20200405234901p:plain:w350