インデックス マージを使用したステートメントの説明
IndexMerge
は、テーブルにアクセスするために TiDB v4.0 で導入された方法です。この方法を使用すると、TiDB オプティマイザーはテーブルごとに複数のインデックスを使用し、各インデックスから返された結果をマージできます。一部のシナリオでは、この方法を使用すると、テーブル全体のスキャンが回避されるため、クエリがより効率的になります。
mysql> EXPLAIN SELECT * from t where a = 1 or b = 1;
+-------------------------+----------+-----------+---------------+--------------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------+----------+-----------+---------------+--------------------------------------+
| TableReader_7 | 8000.00 | root | | data:Selection_6 |
| └─Selection_6 | 8000.00 | 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 |
+-------------------------+----------+-----------+---------------+--------------------------------------+
mysql> set @@tidb_enable_index_merge = 1;
mysql> explain select * from t use index(idx_a, idx_b) where a > 1 or b > 1;
+--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
| id | estRows | task | access object | operator info |
+--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
| IndexMerge_16 | 6666.67 | root | | |
| ├─IndexRangeScan_13(Build) | 3333.33 | cop[tikv] | table:t, index:idx_a(a) | range:(1,+inf], keep order:false, stats:pseudo |
| ├─IndexRangeScan_14(Build) | 3333.33 | cop[tikv] | table:t, index:idx_b(b) | range:(1,+inf], keep order:false, stats:pseudo |
| └─TableRowIDScan_15(Probe) | 6666.67 | cop[tikv] | table:t | keep order:false, stats:pseudo |
+--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
上記のクエリでは、フィルター条件はOR
を結合子として使用するWHERE
句です。 IndexMerge
がない場合、テーブルごとに 1 つのインデックスしか使用できません。 a = 1
をインデックスa
にプッシュダウンすることはできません。どちらもb = 1
をインデックスb
にプッシュすることはできません。 t
に大量のデータが存在する場合、全表スキャンは非効率的です。このようなシナリオを処理するために、テーブルにアクセスするためにIndexMerge
が TiDB に導入されました。
IndexMerge
を指定すると、オプティマイザはテーブルごとに複数のインデックスを使用し、各インデックスによって返された結果をマージして、上の図の後者IndexMerge
の実行計画を生成できます。ここで、 IndexMerge_16
演算子は 3 つの子ノードを持ち、そのうちIndexRangeScan_13
とIndexRangeScan_14
は範囲スキャンの結果に基づいて条件を満たすすべてのRowID
を取得し、 TableRowIDScan_15
演算子はこれらのRowID
に従って条件を満たすすべてのデータを正確に読み取ります。 .
IndexRangeScan
/ TableRangeScan
などの特定の範囲のデータに対して実行されるスキャン操作の場合、結果のoperator info
列には、 IndexFullScan
/ TableFullScan
などの他のスキャン操作と比較して、スキャン範囲に関する追加情報が含まれます。上記の例では、 IndexRangeScan_13
演算子のrange:(1,+inf]
は、演算子が 1 から正の無限大までデータをスキャンすることを示します。
ノート:
インデックス マージ機能は、v5.4.0 からデフォルトで有効になっています。つまり、
tidb_enable_index_merge
はON
です。
tidb_enable_index_merge
の設定に関係なく、SQL ヒントUSE_INDEX_MERGE
を使用して、オプティマイザーにインデックス マージを強制的に適用させることができます。フィルター条件にプッシュ ダウンできない式が含まれている場合にインデックス マージを有効にするには、SQL ヒントUSE_INDEX_MERGE
を使用する必要があります。インデックス マージは、論理和正規形 (
or
で接続された式) のみをサポートし、論理和正規形 (and
で接続された式) はサポートしません。現時点では、インデックス マージは一時テーブルではサポートされていません。