決め事として、
- indexed_*** = インデックスが貼ってあるカラム
- unindexed_*** = インデックスが貼ってないカラム
とする。
indexとは
MySQLのデータテーブルにもPostgreSQLと同じようなoidがレコードごとに存在し、indexとは、そのoidとカラムの値を対で持ったシンプルなテーブルみたいなものだと理解すればわかりやすい。
そのカラムだけを見て、どの行が該当するかを判断することができるため、検索負荷が非常に少なく済むのだ。
はじめに、シンプルなSQL
例えばこんなSQL。
SELECT COUNT(indexed_id) FROM sample_table WHERE indexed_column_1 = 1 AND unindex_column_2 > 2 AND indexed_column_3 = 3 ORDER BY indexed_id desc LIMIT 10;
どこにでもよくある文体だけど、これを日本語で表すと
- indexed_id のインデックスを参考に、実レコードの評価をする際のレコードの評価順を降順と定める
- インデックスを参考に indexed_column_1 = 1 を満たすレコードを全て特定する
- 上記までで特定した範囲で、最初に決めた評価順でunindex_column_2 > 2 を満たす実レコードを全て特定する
- 上記で抽出した実レコードから、インデックスを参考に indexed_column_3 = 3 の実レコードを全て抽出する
- 上記で抽出した実レコードから、最初に決めた評価順で先頭から探し、最大10件抽出する
- 特定したレコードのindexed_id の数を算出する
となる。
基礎条件:インデックスに乗ってないカラムのWHERE条件はできる限り後ろに
これを、こう書き換えると
SELECT COUNT(indexed_id) FROM sample_table WHERE indexed_column_1 = 1 AND indexed_column_3 = 3 AND unindex_column_2 > 2 ORDER BY indexed_id desc LIMIT 10;
こんな日本語になる。
- indexed_id のインデックスを参考に、実レコードの評価をする際のレコードの評価順を降順と定める
- 上記まででインデックスを参考に indexed_column_1 = 1 を満たすレコードを全て特定する
- 上記までで特定した範囲で、インデックスを参考に indexed_column_3 = 3 を満たすレコードを全て特定する
- 上記までで特定した範囲で、最初に決めた評価順でunindex_column_2 > 2 を満たすレコードを先頭から探し、最大10件特定する
- 特定したレコードのindexed_id の数を算出する
どちらが処理コストが少ないかは自明で、レコード数が多くなればなるほどその傾向は顕著になるのだ。