私はほとんどの開発者が行うようにインデックスを使用します(主に...よく!インデックス)が、インデックスを使用してデータベースを最適化する微妙な方法がたくさんあると確信しています。DBMSの実装に固有のものかどうかはわかりません。
私の質問は次のとおりです。インデックスの使用方法の良い例は何ですか(基本的な明らかな場合を除く)。また、テーブルにインデックスを指定すると、DBMSはどのようにデータベースを最適化しますか?
私はほとんどの開発者が行うようにインデックスを使用します(主に...よく!インデックス)が、インデックスを使用してデータベースを最適化する微妙な方法がたくさんあると確信しています。DBMSの実装に固有のものかどうかはわかりません。
私の質問は次のとおりです。インデックスの使用方法の良い例は何ですか(基本的な明らかな場合を除く)。また、テーブルにインデックスを指定すると、DBMSはどのようにデータベースを最適化しますか?
回答:
インデックスを「目次」と考えてください。これは、ファイル内の位置へのポインタ、つまりオフセットの順序付きリストです。テーブルに何百万ものレコードが保存されており、一致する条件をテーブルで検索するのではなく、一致する順序付きリストを参照してから、一致する特定の行へのポインタをスタックする方がはるかに高速です。インデックスの完璧な例は、テーブルの主キーフィールド、最も一般的には「id」フィールドです。行ID#11234566が必要な場合、位置11234566のデータソースをスキャンするよりも、データへのポインタをインデックスに要求する方がはるかに高速です。
インデックス作成のそれほど明白ではない使用法は次のとおりです。
CREATE TABLE activity_log (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
activity_type_id SMALLINT UNSIGNED NOT NULL,
datetime_created DATETIME
KEY(activity_type_id),
PRIMARY KEY(id)
);
CREATE TABLE activity_log_to_date_key (
activity_log_id INT UNSIGNED NOT NULL,
date_created_key INT UNSIGNED NOT NULL REFERENCES dim_datetime(id),
UNIQUE KEY(activity_log_id),
KEY(date_created_key)
);
CREATE TABLE dim_datetime (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
date_hour DATETIME NOT NULL,
PRIMARY KEY(id),
KEY(date_hour)
);
操作ではログレコードを作成できますが、ログテーブルよりも検索/ソートが速いインデックス付き日時への参照を作成します。次に、ログテーブルを独自のプライマリキーに戻します。これを拡張する必要がある場合は、お知らせください。これが理にかなっていることを願っています。
サンプルクエリ:
SELECT a.activity_log_id, al.activity_type_id, al.datetime_created
FROM activity_log_to_date_key a
INNER JOIN dim_datetime d ON (d.id = a.date_created_key)
LEFT JOIN activity_log al ON (al.id = a.activity_log_id)
WHERE d.date_hour BETWEEN '2009-01-01 00:00:00' AND '2009-06-01 12:00:00';
多くの人が見逃しているように思える点の1つは、DBMSがクエリのテーブル参照ごとに1つのインデックスしか使用しない(または使用できる)だけであり、複数のインデックスを使用できる場合、組み合わせを使用する方が高速であることですインデックスが存在する場合。
たとえば、大きなテーブルで行を検索する場合、WHERE AnIntegerColumn = 42 AND AnOtherInt = 69
それらの行への最速ルートは、2つの列AnIntegerColumnおよびAnOtherIntのインデックスになります。個別のインデックスのみがあり、結合インデックスがない場合、DBはどちらか一方のインデックスを検索し、2番目の句で結果を個別にフィルタリングするか、両方をスキャンして後で結果をマージします。
複合インデックスで改善できるもう1つの一般的な簡単な操作WHERE SomeColumn = <SomeValue> ORDER BY SomeOtherColumn
は次のとおりです。SomeColumnおよびSomeOtherColumnに(正しい順序で)インデックスがある場合、状況によってはフィルタリング操作と順序付け操作を同時に実行できます。
インデックスの追加が多すぎると、最適化が不適切になる可能性があります。インデックスを格納するために使用される余分なスペース(およびDBが多数の書き込み操作を認識する場合にそれらを維持するIOロード)は、最適ではない読み取りクエリよりも悪い問題になる可能性があります、無理をしないでください。
デビッドとランディはこれをカバーしています。このEXPLAIN
コマンドは、インデックスの作成によって大きな節約が得られるタイミングを判断するうえで、またどのインデックスが必要かを提案する際に大きな助けになると付け加えました。クエリを実行するためにデータベースが実行しているステップが表示されるため、どのビットが最も時間がかかっているかがわかります。
ここでまだ言及していないことは、複数のディスクがある場合、データが実際にある場所とは異なるディスクにインデックスを配置したいということです。これにより、一部の操作が高速化されます。これは、それ自体が正しいのかという疑問に値すると思います。