用 EXPLAIN 查看索引合并的 SQL 执行计划

索引合并是从 TiDB v4.0 起引入的一种新的表访问方式。在这种访问方式下,TiDB 优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并。在某些场景下,这种访问方式能够减少大量不必要的数据扫描,提升查询的执行效率。

开启索引合并

在 v5.4.0 及以上版本的新建集群中,索引合并默认开启。在其他情况下如果未开启,可将 tidb_enable_index_merge 的值设为 ON 来开启索引合并功能。

  1. SET session tidb_enable_index_merge = ON;

示例

  1. EXPLAIN SELECT * FROM t WHERE a = 1 OR b = 1;
  2. +-------------------------+----------+-----------+---------------+--------------------------------------+
  3. | id | estRows | task | access object | operator info |
  4. +-------------------------+----------+-----------+---------------+--------------------------------------+
  5. | TableReader_7 | 8000.00 | root | | data:Selection_6 |
  6. | └─Selection_6 | 8000.00 | cop[tikv] | | or(eq(test.t.a, 1), eq(test.t.b, 1)) |
  7. | └─TableFullScan_5 | 10000.00 | cop[tikv] | table:t | keep order:false, stats:pseudo |
  8. +-------------------------+----------+-----------+---------------+--------------------------------------+
  9. EXPLAIN SELECT /*+ USE_INDEX_MERGE(t) */ * FROM t WHERE a > 1 OR b > 1;
  10. +--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
  11. | id | estRows | task | access object | operator info |
  12. +--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
  13. | IndexMerge_16 | 6666.67 | root | | |
  14. | ├─IndexRangeScan_13(Build) | 3333.33 | cop[tikv] | table:t, index:idx_a(a) | range:(1,+inf], keep order:false, stats:pseudo |
  15. | ├─IndexRangeScan_14(Build) | 3333.33 | cop[tikv] | table:t, index:idx_b(b) | range:(1,+inf], keep order:false, stats:pseudo |
  16. | └─TableRowIDScan_15(Probe) | 6666.67 | cop[tikv] | table:t | keep order:false, stats:pseudo |
  17. +--------------------------------+---------+-----------+-------------------------+------------------------------------------------+

例如,在上述示例中,过滤条件是使用 OR 条件连接的 WHERE 子句。在启用索引合并前,每个表只能使用一个索引,不能将 a = 1 下推到索引 a,也不能将 b = 1 下推到索引 b。当 t 中存在大量数据时,全表扫描的效率会很低。针对这类场景,TiDB 引入了对表的新访问方式:索引合并。

在索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 IndexMerge_16 算子有三个子节点,其中 IndexRangeScan_13IndexRangeScan_14 根据范围扫描得到符合条件的所有 RowID,再由 TableRowIDScan_15 算子根据这些 RowID 精确地读取所有满足条件的数据。

其中对于 IndexRangeScan/TableRangeScan 一类按范围进行的扫表操作,EXPLAIN 表中 operator info 列相比于其他扫表操作,多了被扫描数据的范围这一信息。比如上面的例子中,IndexRangeScan_13 算子中的 range:(1,+inf] 这一信息表示该算子扫描了从 1 到正无穷这个范围的数据。

注意:

  • TiDB 的索引合并特性在 v5.4.0 及之后的版本默认开启,即 tidb_enable_index_mergeON
  • 如果查询中使用了 SQL 优化器 Hint USE_INDEX_MERGE ,无论 tidb_enable_index_merge 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint USE_INDEX_MERGE 才能开启索引合并。
  • 索引合并目前仅支持析取范式(or 连接的表达式),不支持合取范式(and 连接的表达式)。
  • 索引合并目前无法在临时表上使用。

其他类型查询的执行计划