MySQL 8.0 リファレンスマニュアル


8.2.1.13 条件フィルタ

結合処理では、接頭辞行は、結合のあるテーブルから次のテーブルに渡される行です。 通常、オプティマイザは、行の組合せの数が急速に増加しないように、接頭辞数が少ないテーブルを結合順序の早い段階に配置しようとします。 オプティマイザがあるテーブルから選択されて次のテーブルに渡される行の条件に関する情報を使用できる範囲では、行の見積りをより正確に計算し、最適な実行計画を選択できます。

条件フィルタリングを使用しない場合、テーブルの接頭辞行数は、オプティマイザが選択したアクセス方法に応じて、WHERE 句によって選択された推定行数に基づきます。 条件フィルタリングを使用すると、オプティマイザは、アクセス方法で考慮されない他の関連条件を WHERE 句で使用できるため、接頭辞の行数の見積りが改善されます。 たとえば、結合で現在のテーブルから行を選択するために使用できるインデックスベースのアクセス方法がある場合でも、次のテーブルに渡される行を修飾するための見積りをフィルタ (さらに制限) できる、WHERE 句内のテーブルに対する追加の条件が存在する可能性があります。

条件は、次の場合にのみフィルタリング推定に寄与します:

  • 現在のテーブルを参照します。

  • これは、定数値または結合順序内の以前のテーブルの値に依存します。

  • アクセス方法ではまだ考慮されていません。

EXPLAIN 出力では、rows カラムに選択したアクセス方法の行の見積りが示され、filtered カラムに条件フィルタの効果が反映されます。filtered 値はパーセンテージで表されます。 最大値は 100 で、これは行のフィルタリングが行われなかったことを意味します。 100 から減少する値は、フィルタリングの量が増加していることを示します。

接頭辞の行数 (結合で現在のテーブルから次のテーブルに渡されると推定される行数) は、rows 値と filtered 値の積です。 つまり、接頭辞の行数は推定された行数で、推定されたフィルタリング効果によって削減されます。 たとえば、rows が 1000 で、filtered が 20% の場合、条件フィルタリングによって 1000 の推定行数が接頭辞の行数 1000× 20% = 1000× .2 = 200 に削減されます。

次のクエリーを考慮してください。

SELECT *
  FROM employee JOIN department ON employee.dept_no = department.dept_no
  WHERE employee.first_name = 'John'
  AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01';

データセットに次の特性があるとします:

  • employee テーブルには 1024 行あります。

  • department テーブルには 12 行あります。

  • どちらのテーブルにも、dept_no のインデックスがあります。

  • employee テーブルには、first_name のインデックスがあります。

  • employee.first_name では、8 行が次の条件を満たします:

    employee.first_name = 'John'
  • 150 行が employee.hire_date で次の条件を満たしています:

    employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01'
  • 1 行が両方の条件を満たしています:

    employee.first_name = 'John'
    AND employee.hire_date BETWEEN '2018-01-01' AND '2018-06-01'

条件フィルタリングを使用しない場合、EXPLAIN は次のような出力を生成します:

+----+------------+--------+------------------+---------+---------+------+----------+
| id | table      | type   | possible_keys    | key     | ref     | rows | filtered |
+----+------------+--------+------------------+---------+---------+------+----------+
| 1  | employee   | ref    | name,h_date,dept | name    | const   | 8    | 100.00   |
| 1  | department | eq_ref | PRIMARY          | PRIMARY | dept_no | 1    | 100.00   |
+----+------------+--------+------------------+---------+---------+------+----------+

employee の場合、name インデックスのアクセス方法では、'John'の名前と一致する 8 行が取得されます。 フィルタリングは行われない (filtered は 100%) ため、すべての行が次のテーブルの接頭辞行になります: 接頭辞の行数は、rows× filtered = 8× 100% = 8 です。

条件フィルタリングを使用すると、オプティマイザでは、アクセス方法で考慮されない WHERE 句の条件も考慮されます。 この場合、オプティマイザはヒューリスティックを使用して、employee.hire_date での BETWEEN 条件に対する 16.31 % のフィルタリング効果を見積もります。 その結果、EXPLAIN では次のような出力が生成されます:

+----+------------+--------+------------------+---------+---------+------+----------+
| id | table      | type   | possible_keys    | key     | ref     | rows | filtered |
+----+------------+--------+------------------+---------+---------+------+----------+
| 1  | employee   | ref    | name,h_date,dept | name    | const   | 8    | 16.31    |
| 1  | department | eq_ref | PRIMARY          | PRIMARY | dept_no | 1    | 100.00   |
+----+------------+--------+------------------+---------+---------+------+----------+

接頭辞の行数は、実際のデータセットをより厳密に反映した rows× filtered = 8× 16.31 % = 1.3,になりました。

通常、オプティマイザでは、行を渡す次のテーブルがないため、最後に結合されたテーブルの条件フィルタリング効果 (接頭辞行数の削減) は計算されません。 EXPLAIN で例外が発生しました: 詳細情報を提供するために、最後の結合テーブルを含むすべての結合テーブルのフィルタリング効果が計算されます。

オプティマイザが追加のフィルタリング条件を考慮するかどうかを制御するには、optimizer_switch システム変数の condition_fanout_filter フラグを使用します (セクション8.9.2「切り替え可能な最適化」 を参照)。 このフラグはデフォルトで有効になっていますが、条件フィルタリングを抑制するために無効にできます (たとえば、特定のクエリーでパフォーマンスが向上することが判明した場合)。

オプティマイザが条件フィルタリングの影響を過度に見積もる場合、条件フィルタリングが使用されていない場合よりもパフォーマンスが低下する可能性があります。 このような場合は、次の方法が役立ちます:

  • カラムがインデックス付けされていない場合は、オプティマイザがカラム値の分散に関する情報を取得し、その行の見積りを改善できるようにインデックス付けします。

  • 同様に、使用可能なカラムヒストグラム情報がない場合は、ヒストグラムを生成します (セクション8.9.6「オプティマイザ統計」 を参照)。

  • 結合順序を変更します。 これを実現する方法には、結合順序オプティマイザヒント (セクション8.9.3「オプティマイザヒント」 を参照)、SELECT 直後の STRAIGHT_JOIN および STRAIGHT_JOIN 結合演算子が含まれます。

  • セッションの条件フィルタリングを無効にします:

    SET optimizer_switch = 'condition_fanout_filter=off';

    または、特定のクエリーに対して、オプティマイザヒントを使用します:

    SELECT /*+ SET_VAR(optimizer_switch = 'condition_fanout_filter=off') */ ...

関連キーワード:  テーブル, 条件, インデックス, 結合, オプティマイザ, InnoDB, employee, 方法, フィルタ, ステートメント