アクセス述語とフィルタ述語の見分け方


MySQLは、where句(述語)を適用するのに、 3つの方法を使い分けます。

アクセス述語 (「key_len」 列)

アクセス述語は、リーフノードの走査の開始と終了の条件を 表しています。

インデックスフィルタ述語 (MySQL 5.6以降の 「Using index condition」)

インデックスフィルタ述語は、リーフノード走査の時にのみ適用されます。 スキャンされる範囲の開始と終了の条件を表したり、 範囲を狭めるものとしては使われません。

テーブルレベルのフィルタ述語 (「Extra」列の「Using where」)

インデックスの一部でない列に対する述語は、 テーブルのレベルで評価されます。その場合データベースは、 まずテーブルから行をロードしなければなりません。

MySQLの実行計画は、各条件に対してどの述語タイプが使われるかは 表示してくれません。使用されている述語タイプを列挙するだけです。

次の例では、where句全体が アクセス述語として使われています。

CREATE TABLE demo (
   id1 NUMERIC
 , id2 NUMERIC
 , id3 NUMERIC
 , val NUMERIC);
INSERT INTO demo VALUES (1,1,1,1);
INSERT INTO demo VALUES (2,2,2,2);
CREATE INDEX demo_idx
          ON demo
             (id1, id2, id3);
EXPLAIN
 SELECT * 
   FROM demo
  WHERE id1=1
    AND id2=1;
+------+----------+---------+-------------+------+-------+
| type | key      | key_len | ref         | rows | Extra |
+------+----------+---------+-------------+------+-------+
| ref  | demo_idx | 12      | const,const |    1 |       |
+------+----------+---------+-------------+------+-------+

「Extra」列には、「Using where」も「Using index condition」も 表示されていません。しかしインデックスは使われており (type=ref, key=demo_idx)、where句全体が アクセス述語になっているであろう事が分かります。

初心者からエキスパートまで役に立つ内容です。
特に駆け出しのエンジニアは持っておくといい

ref列が、インデックスから2つの列を使っていることを 示しているかも確認してください。インデックスのどの部分が使われているかを確認するもうひとつの 方法は、key_lenの値を見ることです。ここでは、このクエリはインデックスの定義の 最初の12バイトを使っていると表示されています。これを列名に対応付けるには、各列が どのくらいのストレージ容量を使用するかを「とにかく」知っておかなければなりません(MySQLの ドキュメントのデータ型のストレージ要件 も参照してください)。NOT NULL制約がない場合、MySQLは各列に追加の容量を 必要とします。結局、 NUMERICの各列は、例では6バイトが必要です。従って、 キー長の12バイトは、アクセス述語としてインデックスの列の最初の2つを使っているという ことになります。

(ID2の代わりに)ID3でフィルタすると、 MySQL 5.6以降ではインデックスフィルタ述語(「Using index condition」)を使います。

EXPLAIN
 SELECT * 
   FROM demo
  WHERE id1=1
    AND id3=1
+------+----------+---------+-------+------+-----------------------+
| type | key      | key_len | ref   | rows | Extra                 |
+------+----------+---------+-------+------+-----------------------+
| ref  | demo_idx | 6       | const |    1 | Using index condition |
+------+----------+---------+-------+------+-----------------------+

この場合、ken_len=6およびref列に ひとつだけあるconstは、ひとつの列だけがアクセス述語として使われているという 事を示しています。

5.5以前のMySQLバージョンでは、このクエリはテーブルレベルの フィルタ述語になります。これは、「Extra」列に「Using where」が出る事から分かります。

+------+----------+---------+-------+------+-------------+
| type | key      | key_len | ref   | rows | Extra       |
+------+----------+---------+-------+------+-------------+
| ref  | demo_idx | 6       | const |    1 | Using where |
+------+----------+---------+-------+------+-------------+

ヒント

Photo of Markus Winand
Markus Winand氏は、開発者がSQLパフォーマンスを改善するお手伝いをしています。 彼は、SQL Performance Explainedの 著者でもあり、出張トレーニングhttp://winand.at/での リモート講義も 行っています。