インデックス マージを使用した Explain ステートメント

インデックス マージは、テーブルにアクセスするために TiDB v4.0 で導入された方法です。この方法を使用すると、TiDB オプティマイザーはテーブルごとに複数のインデックスを使用し、各インデックスから返された結果をマージできます。一部のシナリオでは、この方法によりテーブル全体のスキャンが回避され、クエリがより効率的になります。

TiDB のインデックスマージには、交差型と共用型の 2 種類があります。前者はAND式に適用され、後者はOR式に適用されます。 Union タイプのインデックス マージは、実験的機能として TiDB v4.0 に導入され、v5.4.0 で GA になりました。交差タイプは TiDB v6.5.0 で導入され、 USE_INDEX_MERGEヒントが指定されている場合にのみ使用できます。

インデックスのマージを有効にする

v5.4.0 以降の TiDB バージョンでは、インデックスのマージがデフォルトで有効になっています。その他の状況で、インデックスのマージが有効になっていない場合は、変数tidb_enable_index_mergeからONを設定してこの機能を有効にする必要があります。

SET session tidb_enable_index_merge = ON;

CREATE TABLE t(a int, b int, c int, d int, INDEX idx_a(a), INDEX idx_b(b), INDEX idx_c(c), INDEX idx_d(d));
EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a = 1 OR b = 1; +-------------------------+----------+-----------+---------------+--------------------------------------+ | id | estRows | task | access object | operator info | +-------------------------+----------+-----------+---------------+--------------------------------------+ | TableReader_7 | 19.99 | root | | data:Selection_6 | | └─Selection_6 | 19.99 | cop[tikv] | | or(eq(test.t.a, 1), eq(test.t.b, 1)) | | └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | +-------------------------+----------+-----------+---------------+--------------------------------------+ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t) */ * FROM t WHERE a > 1 OR b > 1; +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+ | id | estRows | task | access object | operator info | +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+ | IndexMerge_8 | 5555.56 | root | | type: union | | ├─IndexRangeScan_5(Build) | 3333.33 | cop[tikv] | table:t, index:idx_a(a) | range:(1,+inf], keep order:false, stats:pseudo | | ├─IndexRangeScan_6(Build) | 3333.33 | cop[tikv] | table:t, index:idx_b(b) | range:(1,+inf], keep order:false, stats:pseudo | | └─TableRowIDScan_7(Probe) | 5555.56 | cop[tikv] | table:t | keep order:false, stats:pseudo | +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+

前述のクエリでは、フィルター条件は、コネクタとしてORを使用するWHERE句です。インデックスのマージを使用しない場合、テーブルごとに使用できるインデックスは 1 つだけです。 a = 1インデックスaにプッシュダウンすることはできません。 b = 1インデックスbにプッシュダウンすることもできません。 tに大量のデータが存在する場合、フル テーブル スキャンは非効率的です。このようなシナリオに対処するために、テーブルにアクセスするためにインデックス マージが TiDB に導入されました。

前述のクエリの場合、オプティマイザはテーブルにアクセスするために共用体タイプのインデックス マージを選択します。インデックスのマージにより、オプティマイザはテーブルごとに複数のインデックスを使用し、各インデックスから返された結果をマージし、前の出力で後の実行プランを生成できます。

出力では、 IndexMerge_8演算子のうちoperator infotype: union情報は、この演算子が共用体タイプのインデックス マージであることを示しています。 3 つの子ノードがあります。 IndexRangeScan_5IndexRangeScan_6範囲に従って条件を満たすRowID秒をスキャンし、 TableRowIDScan_7オペレーターはこれらRowID秒に従って条件を満たすすべてのデータを正確に読み取ります。

IndexRangeScan / TableRangeScanなどの特定のデータ範囲に対して実行されるスキャン操作の場合、結果のoperator info列には、 IndexFullScan / TableFullScanなどの他のスキャン操作と比較して、スキャン範囲に関する追加情報が含まれます。上記の例では、 IndexRangeScan_5演算子のrange:(1,+inf] 、演算子が 1 から正の無限大までデータをスキャンすることを示します。

EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a > 1 AND b > 1 AND c = 1; -- Does not use index merge +--------------------------------+---------+-----------+-------------------------+---------------------------------------------+ | id | estRows | task | access object | operator info | +--------------------------------+---------+-----------+-------------------------+---------------------------------------------+ | IndexLookUp_19 | 1.11 | root | | | | ├─IndexRangeScan_16(Build) | 10.00 | cop[tikv] | table:t, index:idx_c(c) | range:[1,1], keep order:false, stats:pseudo | | └─Selection_18(Probe) | 1.11 | cop[tikv] | | gt(test.t.a, 1), gt(test.t.b, 1) | | └─TableRowIDScan_17 | 10.00 | cop[tikv] | table:t | keep order:false, stats:pseudo | +--------------------------------+---------+-----------+-------------------------+---------------------------------------------+ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a > 1 AND b > 1 AND c = 1; -- Uses index merge +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+ | id | estRows | task | access object | operator info | +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+ | IndexMerge_9 | 1.11 | root | | type: intersection | | ├─IndexRangeScan_5(Build) | 3333.33 | cop[tikv] | table:t, index:idx_a(a) | range:(1,+inf], keep order:false, stats:pseudo | | ├─IndexRangeScan_6(Build) | 3333.33 | cop[tikv] | table:t, index:idx_b(b) | range:(1,+inf], keep order:false, stats:pseudo | | ├─IndexRangeScan_7(Build) | 10.00 | cop[tikv] | table:t, index:idx_c(c) | range:[1,1], keep order:false, stats:pseudo | | └─TableRowIDScan_8(Probe) | 1.11 | cop[tikv] | table:t | keep order:false, stats:pseudo | +-------------------------------+---------+-----------+-------------------------+------------------------------------------------+

前の例から、フィルター条件はANDコネクタとして使用するWHERE句であることがわかります。インデックスのマージが有効になる前は、オプティマイザは 3 つのインデックス ( idx_aidx_b 、またはidx_c ) の 1 つだけを選択できます。

いずれかのフィルター条件の選択性が低い場合、オプティマイザーは対応するインデックスを直接選択して、理想的な実行効率を実現します。ただし、データ分布が次の 3 つの条件をすべて満たす場合は、交差型インデックス マージの使用を検討できます。

  • テーブル全体のデータサイズは大きく、テーブル全体を直接読み込むのは非効率です。
  • 3 つのフィルター条件のそれぞれについて、それぞれの選択性が非常に高いため、単一のインデックスを使用したIndexLookUpの実行効率は理想的ではありません。
  • 3 つのフィルター条件の全体的な選択性は低くなります。

交差タイプのインデックス マージを使用してテーブルにアクセスする場合、オプティマイザはテーブルで複数のインデックスを使用することを選択し、各インデックスから返された結果をマージして、前の出力例の後半IndexMergeの実行プランを生成できます。 operator info of IndexMerge_9演算子のtype: intersection情報は、この演算子が交差タイプのインデックス マージであることを示します。実行プランの他の部分は、前述の共用体タイプのインデックスのマージの例と似ています。

注記:

  • インデックス マージ機能は、v5.4.0 からデフォルトで有効になっています。つまり、 tidb_enable_index_mergeONです。

  • SQL ヒントUSE_INDEX_MERGE使用すると、 tidb_enable_index_mergeの設定に関係なく、オプティマイザにインデックス マージを強制的に適用できます。フィルター条件にプッシュダウンできない式が含まれている場合にインデックスのマージを有効にするには、SQL ヒントUSE_INDEX_MERGEを使用する必要があります。

  • オプティマイザがクエリ プランに対して単一インデックス スキャン方法 (フル テーブル スキャン以外) を選択できる場合、オプティマイザは自動的にインデックス マージを使用しません。オプティマイザーがインデックスのマージを使用するには、オプティマイザー ヒントを使用する必要があります。

  • 現時点では、インデックス マージは一時配列テーブルではサポートされていません。

  • 交差タイプのインデックス マージは、オプティマイザによって自動的に選択されません。テーブル名とインデックス名を選択するには、 USE_INDEX_MERGEヒントを使用してテーブル名とインデックス名を指定する必要があります。

このページは役に立ちましたか?