SQL Serverでインデックスがどのように機能するか、特に包含列を理解している人はほとんどいないことに気付きました。それでも、インデックスはクエリを最適化するための優れた方法です。最初は、含まれている列についてもわかりませんでしたが、実験の結果、非常に便利であることがわかりました。
次のテーブルとクエリがあるとします。
CREATE TABLE Person ( PersonID int, FirstName varchar(100), LastName varchar(100), Age int, … … ) SELECT FirstName, LastName, Age FROM Person WHERE FirstName = 'John' and LastName = 'Smith'
PersonIDが主キーであることは明らかです。名と名前のインデックスがあるとします。これをIX_Person_FirstNameLastNameと呼びましょう。このようなクエリの実行プランは次のようになります。
- IX_Person_FirstNameLastNameインデックスツリーを使用して、指定された姓と名のすべての行を検索します
- インデックスの葉のディスク上の線の実際の位置を検出し、実際の位置に移動して年齢を読み取ります。
ここで、このクエリが非常に頻繁に実行されると考えてみましょう。毎回2つのステップを実行する必要があります。最適化できますか? MS SQL Serverの場合、問題はありません。INCLUDEオプションを使用して、インデックスに値を直接含めることができます。
CREATE INDEX IX_PERSON ON Person ( FirstName, LastName ) INCLUDE(Age)
現在、このフィールドはインデックス作成中には使用されませんが、インデックスに含まれます。この点で私たちはどのような問題に直面することができますか?特定のフィールドでテーブルにインデックスを付ける場合、データベースサーバーはこのフィールドでインデックスツリーを構築する必要があります。これは、値を変更するときにインデックスツリーを変更する必要があることを意味します。値を集中的に変更すると、サーバーにとって問題のある困難な作業になります。更新が大規模になりすぎると、インデックスを削除する方が簡単な場合があります。インデックスは検索を大幅に最適化しますが、挿入、削除、更新の操作に悪影響を及ぼします。
フィールドが単にインデックスに含まれている場合、インデックスツリーの構築中には使用されず、影響はありませんが、値はこの木の葉で簡単に見つけることができます。姓名による検索が行われると、サーバーはツリーからすべての名と姓を検索し、リーフに到達すると(必要なインデックス値を見つけます)、物理的な場所へのポインターに加えて検索します。行の値のうち、インデックスに含まれるフィールド値も含まれます。これは、回線の物理的な場所に切り替えてそこから読み取るための2番目の手順を実行する必要がないことを意味します。
年齢データを変更するときにツリーを変更する必要がないため、これらすべてがデータ変更操作に大きな影響を与えることはありません。インデックスを変更する必要はありません。ツリーリーフの値を変更するだけです。そのため、年齢フィールドを大幅に変更しても、パフォーマンスに大きな影響はありません。確かに影響はありますが、それほどではありません。
私の知る限り、クラスター化されたインデックスの値は自動的にリーフレベルに含まれますが、これは仕様で確認する必要があります。
では、含まれているフィールドの使用が有益なのはいつですか?クエリ結果で頻繁に使用されるが、時々変更される場合。例は銀行取引の表です。このようなテーブルは、アカウント番号、トランザクションタイプ、日付、合計のフィールドで構成されている場合があります。合計によるインデックス作成には意味がありませんが、インデックスに含めることができ、クエリが大幅に高速化されます。
インデックス作成から実際の効果を取得するには、クエリですべてのフィールドを選択する必要はありません。つまり、SELECT*FROMテーブルを忘れる必要があります。常に本当に必要なフィールドのみを再計算してください。そして、それらの値がインデックスに含まれるようになると、実行速度がかなり速くなる可能性があります。
便利なツール:
dbForge Index Manager – SQLインデックスのステータスを分析し、インデックスの断片化に関する問題を修正するための便利なSSMSアドイン。