結合処理では、接頭辞行は、結合のあるテーブルから次のテーブルに渡される行です。 通常、オプティマイザは、行の組合せの数が急速に増加しないように、接頭辞数が少ないテーブルを結合順序の早い段階に配置しようとします。 オプティマイザがあるテーブルから選択されて次のテーブルに渡される行の条件に関する情報を使用できる範囲では、行の見積りをより正確に計算し、最適な実行計画を選択できます。
条件フィルタリングを使用しない場合、テーブルの接頭辞行数は、オプティマイザが選択したアクセス方法に応じて、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') */ ...