From 7935cb7db96d17661a4a518a81f9f7d32a4f7585 Mon Sep 17 00:00:00 2001
From: time-and-fate <25057648+time-and-fate@users.noreply.github.com>
Date: Wed, 23 Nov 2022 16:54:10 +0800
Subject: [PATCH 01/11] add
---
explain-index-merge.md | 63 ++++++++++++++++++++++++++++++++----------
optimizer-hints.md | 8 ++----
2 files changed, 52 insertions(+), 19 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index a7eb90b5cfde..f4ecd500b28e 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -7,6 +7,8 @@ summary: 了解 TiDB 中 EXPLAIN 语句返回的执行计划信息。
索引合并是从 TiDB v4.0 起引入的一种新的表访问方式。在这种访问方式下,TiDB 优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并。在某些场景下,这种访问方式能够减少大量不必要的数据扫描,提升查询的执行效率。
+TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `and` 连接的表达式和由 `or` 连接的表达式。其中,并集型索引合并从 TiDB v4.0 起引入;交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
+
## 开启索引合并
在 v5.4.0 及以上版本的新建集群中,索引合并默认开启。在其他情况下如果未开启,可将 `tidb_enable_index_merge` 的值设为 `ON` 来开启索引合并功能。
@@ -20,37 +22,70 @@ SET session tidb_enable_index_merge = ON;
## 示例
```sql
-EXPLAIN SELECT * FROM t WHERE a = 1 OR b = 1;
+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));
+```
+
+```sql
+EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * 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)) |
+| 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_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 |
-+--------------------------------+---------+-----------+-------------------------+------------------------------------------------+
++-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
+| 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` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。针对这类场景,TiDB 引入了对表的新访问方式:索引合并。
+例如,在上述示例中,过滤条件是使用 `OR` 条件连接的 `WHERE` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。
-在索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 `IndexMerge_16` 算子有三个子节点,其中 `IndexRangeScan_13` 和 `IndexRangeScan_14` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_15` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
+在并集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
其中对于 `IndexRangeScan`/`TableRangeScan` 一类按范围进行的扫表操作,`EXPLAIN` 表中 `operator info` 列相比于其他扫表操作,多了被扫描数据的范围这一信息。比如上面的例子中,`IndexRangeScan_13` 算子中的 `range:(1,+inf]` 这一信息表示该算子扫描了从 1 到正无穷这个范围的数据。
+```sql
+EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a > 1 AND b > 1 AND c = 1;
++--------------------------------+---------+-----------+-------------------------+---------------------------------------------+
+| 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;
++-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
+| 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` 子句。在启用索引合并前,我们只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
+
+如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但是考虑数据分布如下的情形:全表的数据量相当大,导致直接读全表的执行效率非常低下;三个过滤条件的过滤性都非常差,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想;但是三个过滤条件整体的过滤性非常好。此时,可以考虑使用交集型索引合并。
+
+在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上示例中后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
+
> **注意:**
>
> - TiDB 的索引合并特性在 v5.4.0 及之后的版本默认开启,即 [`tidb_enable_index_merge`](/system-variables.md#tidb_enable_index_merge-从-v40-版本开始引入) 为 `ON`。
> - 如果查询中使用了 SQL 优化器 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) ,无论 `tidb_enable_index_merge` 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) 才能开启索引合并。
-> - 索引合并目前仅支持析取范式(`or` 连接的表达式),不支持合取范式(`and` 连接的表达式)。
+> - 如果查询有除了全表扫以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能使用 Hint 指定。
> - 索引合并目前无法在临时表上使用。
+> - 交集型索引合并目前不会被优化器自动选择,必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定**表名和索引名**时才会选择。
## 其他类型查询的执行计划
diff --git a/optimizer-hints.md b/optimizer-hints.md
index 160aa4acd4a5..4fa04101861e 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -358,7 +358,9 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
### USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])
-`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过 index merge 的方式来访问指定的表,其中索引列表为可选参数。若显式地指出索引列表,会尝试在索引列表中选取索引来构建 index merge。若不给出索引列表,会尝试在所有可用的索引中选取索引来构建 index merge。例如:
+`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过 [index merge](/explain-index-merge.md) 的方式来访问指定的表。
+
+对于并集型 index merge,其中索引列表为可选参数,若显式地指出索引列表,会尝试在索引列表中选取索引来构建 index merge。若不给出索引列表,会尝试在所有可用的索引中选取索引来构建 index merge。对于交集型 index merge,索引列表是必选参数。例如:
{{< copyable "sql" >}}
@@ -372,10 +374,6 @@ SELECT /*+ USE_INDEX_MERGE(t1, idx_a, idx_b, idx_c) */ * FROM t1 WHERE t1.a > 10
>
> `USE_INDEX_MERGE` 的参数是索引名,而不是列名。对于主键索引,索引名为 `primary`。
-目前该 Hint 生效的条件较为苛刻,包括:
-
-- 如果查询有除了全表扫以外的单索引扫描方式可以选择,优化器不会选择 index merge;
-
### LEADING(t1_name [, tl_name ...])
`LEADING(t1_name [, tl_name ...])` 提示优化器在生成多表连接的执行计划时,按照 hint 中表名出现的顺序来确定多表连接的顺序。例如:
From 273b6a2ce09fbf282f73e5c841a33a4d1d1e7737 Mon Sep 17 00:00:00 2001
From: time-and-fate <25057648+time-and-fate@users.noreply.github.com>
Date: Wed, 23 Nov 2022 17:00:01 +0800
Subject: [PATCH 02/11] update
---
explain-index-merge.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index f4ecd500b28e..2a252219679c 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -75,7 +75,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,我们只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
-如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但是考虑数据分布如下的情形:全表的数据量相当大,导致直接读全表的执行效率非常低下;三个过滤条件的过滤性都非常差,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想;但是三个过滤条件整体的过滤性非常好。此时,可以考虑使用交集型索引合并。
+如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但是考虑数据分布如下的情形:全表的数据量相当大,导致直接读全表的执行效率非常低下;三个过滤条件的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想;但是三个过滤条件整体的过滤性非常好。此时,可以考虑使用交集型索引合并。
在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上示例中后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
From 25ce870a28caa1aea8258df7a7659e00cf892d18 Mon Sep 17 00:00:00 2001
From: time-and-fate <25057648+time-and-fate@users.noreply.github.com>
Date: Tue, 29 Nov 2022 18:11:02 +0800
Subject: [PATCH 03/11] add new variable
---
system-variables.md | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/system-variables.md b/system-variables.md
index fe953b0646f4..fe46664532e3 100644
--- a/system-variables.md
+++ b/system-variables.md
@@ -1879,6 +1879,15 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告)
- 这个变量用来设置 index lookup join 算法的并发度。
- 默认值 `-1` 表示使用 `tidb_executor_concurrency` 的值。
+### `tidb_index_merge_intersection_concurrency`
+
+- 作用域:SESSION | GLOBAL
+- 是否持久化到集群:是
+- 默认值:`-1`
+- 范围:`[1, 256]`
+- 这个变量用来设置 IndexMerge 进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效,实际并发度为 min(`tidb_index_merge_intersection_concurrency`, 分区表分区数目)
+- 默认值 `-1` 表示使用 `tidb_executor_concurrency` 的值。
+
### `tidb_index_lookup_size`
- 作用域:SESSION | GLOBAL
From 91f446e6d49cb8b2f84636cd38efd0bc1df15e44 Mon Sep 17 00:00:00 2001
From: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com>
Date: Tue, 29 Nov 2022 18:34:00 +0800
Subject: [PATCH 04/11] Apply suggestions from code review
Co-authored-by: TomShawn <41534398+TomShawn@users.noreply.github.com>
---
explain-index-merge.md | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index 2a252219679c..6d1b78e977a1 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -7,7 +7,7 @@ summary: 了解 TiDB 中 EXPLAIN 语句返回的执行计划信息。
索引合并是从 TiDB v4.0 起引入的一种新的表访问方式。在这种访问方式下,TiDB 优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并。在某些场景下,这种访问方式能够减少大量不必要的数据扫描,提升查询的执行效率。
-TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `and` 连接的表达式和由 `or` 连接的表达式。其中,并集型索引合并从 TiDB v4.0 起引入;交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
+TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `AND` 连接的表达式和由 `OR` 连接的表达式。其中,并集型索引合并从 TiDB v4.0 起引入;交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
## 开启索引合并
@@ -47,12 +47,13 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t) */ * FROM t WHERE a > 1 OR b > 1;
例如,在上述示例中,过滤条件是使用 `OR` 条件连接的 `WHERE` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。
-在并集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
+对于以上查询语句,优化器选择了并集型索引合并的方式访问表。在这种访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
其中对于 `IndexRangeScan`/`TableRangeScan` 一类按范围进行的扫表操作,`EXPLAIN` 表中 `operator info` 列相比于其他扫表操作,多了被扫描数据的范围这一信息。比如上面的例子中,`IndexRangeScan_13` 算子中的 `range:(1,+inf]` 这一信息表示该算子扫描了从 1 到正无穷这个范围的数据。
```sql
-EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a > 1 AND b > 1 AND c = 1;
+EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a > 1 AND b > 1 AND c = 1; -- 不使用索引合并
+
+--------------------------------+---------+-----------+-------------------------+---------------------------------------------+
| id | estRows | task | access object | operator info |
+--------------------------------+---------+-----------+-------------------------+---------------------------------------------+
@@ -61,7 +62,9 @@ EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a > 1 AND b > 1 AND c = 1;
| └─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;
+
+EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a > 1 AND b > 1 AND c = 1; -- 使用索引合并
+
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
@@ -73,7 +76,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
```
-在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,我们只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
+在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但是考虑数据分布如下的情形:全表的数据量相当大,导致直接读全表的执行效率非常低下;三个过滤条件的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想;但是三个过滤条件整体的过滤性非常好。此时,可以考虑使用交集型索引合并。
@@ -83,9 +86,9 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
>
> - TiDB 的索引合并特性在 v5.4.0 及之后的版本默认开启,即 [`tidb_enable_index_merge`](/system-variables.md#tidb_enable_index_merge-从-v40-版本开始引入) 为 `ON`。
> - 如果查询中使用了 SQL 优化器 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) ,无论 `tidb_enable_index_merge` 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) 才能开启索引合并。
-> - 如果查询有除了全表扫以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能使用 Hint 指定。
+> - 如果查询有除了全表扫以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能通过 Hint 指定使用索引合并。
> - 索引合并目前无法在临时表上使用。
-> - 交集型索引合并目前不会被优化器自动选择,必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定**表名和索引名**时才会选择。
+> - 交集型索引合并目前不会被优化器自动选择,必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定**表名和索引名**时才会被选择。
## 其他类型查询的执行计划
From ea15715411a611394f830c0ae4737f9bfef87e37 Mon Sep 17 00:00:00 2001
From: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com>
Date: Wed, 30 Nov 2022 11:40:08 +0800
Subject: [PATCH 05/11] Apply suggestions from code review
Co-authored-by: TomShawn <41534398+TomShawn@users.noreply.github.com>
---
explain-index-merge.md | 6 +++++-
optimizer-hints.md | 6 ++++--
system-variables.md | 4 ++--
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index 6d1b78e977a1..4618f4cfaa45 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -78,7 +78,11 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
-如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但是考虑数据分布如下的情形:全表的数据量相当大,导致直接读全表的执行效率非常低下;三个过滤条件的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想;但是三个过滤条件整体的过滤性非常好。此时,可以考虑使用交集型索引合并。
+如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但如果数据分布同时满足以下三种情形,可以考虑使用交集型索引合并:
+
+- 全表的数据量相当大,导致直接读全表的执行效率非常低下
+- 三个过滤条件的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想
+- 三个过滤条件整体的过滤性非常好
在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上示例中后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
diff --git a/optimizer-hints.md b/optimizer-hints.md
index 4fa04101861e..c5801e7afa55 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -358,9 +358,11 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
### USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])
-`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过 [index merge](/explain-index-merge.md) 的方式来访问指定的表。
+`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过 index merge 的方式来访问指定的表。Index merge 分为并集型和交集型两种类型,详情参见[用 EXPLAIN 查看索引合并的 SQL 执行计划](/explain-index-merge.md)。
-对于并集型 index merge,其中索引列表为可选参数,若显式地指出索引列表,会尝试在索引列表中选取索引来构建 index merge。若不给出索引列表,会尝试在所有可用的索引中选取索引来构建 index merge。对于交集型 index merge,索引列表是必选参数。例如:
+对于并集型 index merge,hint 中的索引列表为可选参数,若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建 index merge。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建 index merge。示例如下。
+
+对于交集型 index merge,索引列表是必选参数。
{{< copyable "sql" >}}
diff --git a/system-variables.md b/system-variables.md
index fe46664532e3..bbbd1647011a 100644
--- a/system-variables.md
+++ b/system-variables.md
@@ -1879,13 +1879,13 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告)
- 这个变量用来设置 index lookup join 算法的并发度。
- 默认值 `-1` 表示使用 `tidb_executor_concurrency` 的值。
-### `tidb_index_merge_intersection_concurrency`
+### `tidb_index_merge_intersection_concurrency` 从 v6.5.0 版本开始引入
- 作用域:SESSION | GLOBAL
- 是否持久化到集群:是
- 默认值:`-1`
- 范围:`[1, 256]`
-- 这个变量用来设置 IndexMerge 进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效,实际并发度为 min(`tidb_index_merge_intersection_concurrency`, 分区表分区数目)
+- 这个变量用来设置 IndexMerge 进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效,实际并发度为 `tidb_index_merge_intersection_concurrency` 与分区表分区数目两者中较小的值。
- 默认值 `-1` 表示使用 `tidb_executor_concurrency` 的值。
### `tidb_index_lookup_size`
From 57196e802420069e4bb3c06f6cc78763d40cc9e4 Mon Sep 17 00:00:00 2001
From: time-and-fate <25057648+time-and-fate@users.noreply.github.com>
Date: Wed, 30 Nov 2022 18:59:58 +0800
Subject: [PATCH 06/11] address comments
---
explain-index-merge.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index 4618f4cfaa45..bfba50171a26 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -7,7 +7,7 @@ summary: 了解 TiDB 中 EXPLAIN 语句返回的执行计划信息。
索引合并是从 TiDB v4.0 起引入的一种新的表访问方式。在这种访问方式下,TiDB 优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并。在某些场景下,这种访问方式能够减少大量不必要的数据扫描,提升查询的执行效率。
-TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `AND` 连接的表达式和由 `OR` 连接的表达式。其中,并集型索引合并从 TiDB v4.0 起引入;交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
+TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `AND` 连接的表达式和由 `OR` 连接的表达式。其中,并集型索引合并在 TiDB v4.0 作为实验功能引入,在 v5.4.0 成为正式功能(GA);交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
## 开启索引合并
@@ -81,7 +81,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但如果数据分布同时满足以下三种情形,可以考虑使用交集型索引合并:
- 全表的数据量相当大,导致直接读全表的执行效率非常低下
-- 三个过滤条件的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想
+- 每个过滤条件单独的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想
- 三个过滤条件整体的过滤性非常好
在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上示例中后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
From 608a9673be739c7e45e490eb9fe72f8bb2e52457 Mon Sep 17 00:00:00 2001
From: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com>
Date: Thu, 1 Dec 2022 13:24:25 +0800
Subject: [PATCH 07/11] Apply suggestions from code review
Co-authored-by: Aolin
---
explain-index-merge.md | 10 +++++-----
optimizer-hints.md | 6 +++---
system-variables.md | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index bfba50171a26..eb2dd061be4e 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -7,7 +7,7 @@ summary: 了解 TiDB 中 EXPLAIN 语句返回的执行计划信息。
索引合并是从 TiDB v4.0 起引入的一种新的表访问方式。在这种访问方式下,TiDB 优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并。在某些场景下,这种访问方式能够减少大量不必要的数据扫描,提升查询的执行效率。
-TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `AND` 连接的表达式和由 `OR` 连接的表达式。其中,并集型索引合并在 TiDB v4.0 作为实验功能引入,在 v5.4.0 成为正式功能(GA);交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
+TiDB 中的索引合并分为交集型和并集型两种类型,分别适用于由 `AND` 连接的表达式和由 `OR` 连接的表达式。其中,并集型索引合并在 TiDB v4.0 作为实验功能引入,在 v5.4.0 成为正式功能 (GA)。交集型索引合并从 TiDB v6.5.0 起引入,且必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定才能使用。
## 开启索引合并
@@ -47,7 +47,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t) */ * FROM t WHERE a > 1 OR b > 1;
例如,在上述示例中,过滤条件是使用 `OR` 条件连接的 `WHERE` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。
-对于以上查询语句,优化器选择了并集型索引合并的方式访问表。在这种访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上示例中后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
+对于以上查询语句,优化器选择了并集型索引合并的方式访问表。在这种访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上两个示例中的后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
其中对于 `IndexRangeScan`/`TableRangeScan` 一类按范围进行的扫表操作,`EXPLAIN` 表中 `operator info` 列相比于其他扫表操作,多了被扫描数据的范围这一信息。比如上面的例子中,`IndexRangeScan_13` 算子中的 `range:(1,+inf]` 这一信息表示该算子扫描了从 1 到正无穷这个范围的数据。
@@ -76,7 +76,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
```
-在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`, `idx_b` 和 `idx_c` 三个索引中的一个。
+在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`、`idx_b` 或 `idx_c` 三个索引中的一个。
如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但如果数据分布同时满足以下三种情形,可以考虑使用交集型索引合并:
@@ -84,13 +84,13 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
- 每个过滤条件单独的过滤性都不够好,导致 `IndexLookUp` 使用单个索引的执行效率也不够理想
- 三个过滤条件整体的过滤性非常好
-在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上示例中后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
+在交集型索引合并访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果取交集,生成以上两个示例中的后一个执行计划。此时的 `IndexMerge_9` 算子的 `operator info` 中的 `type: intersection` 表示该算子是一个交集型索引合并算子。该执行计划的其它部分和上述并集型索引合并示例类似。
> **注意:**
>
> - TiDB 的索引合并特性在 v5.4.0 及之后的版本默认开启,即 [`tidb_enable_index_merge`](/system-variables.md#tidb_enable_index_merge-从-v40-版本开始引入) 为 `ON`。
> - 如果查询中使用了 SQL 优化器 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) ,无论 `tidb_enable_index_merge` 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) 才能开启索引合并。
-> - 如果查询有除了全表扫以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能通过 Hint 指定使用索引合并。
+> - 如果查询有除了全表扫描以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能通过 Hint 指定使用索引合并。
> - 索引合并目前无法在临时表上使用。
> - 交集型索引合并目前不会被优化器自动选择,必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定**表名和索引名**时才会被选择。
diff --git a/optimizer-hints.md b/optimizer-hints.md
index c5801e7afa55..0329fb5b6545 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -358,11 +358,11 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
### USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])
-`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过 index merge 的方式来访问指定的表。Index merge 分为并集型和交集型两种类型,详情参见[用 EXPLAIN 查看索引合并的 SQL 执行计划](/explain-index-merge.md)。
+`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过索引合并的方式来访问指定的表。索引合并分为并集型和交集型两种类型,详情参见[用 EXPLAIN 查看索引合并的 SQL 执行计划](/explain-index-merge.md)。
-对于并集型 index merge,hint 中的索引列表为可选参数,若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建 index merge。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建 index merge。示例如下。
+对于并集型索引合并,Hint 中的索引列表为可选参数,若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。示例如下。
-对于交集型 index merge,索引列表是必选参数。
+对于交集型索引合并,索引列表是必选参数。
{{< copyable "sql" >}}
diff --git a/system-variables.md b/system-variables.md
index bbbd1647011a..b52f7618d7aa 100644
--- a/system-variables.md
+++ b/system-variables.md
@@ -1885,8 +1885,8 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告)
- 是否持久化到集群:是
- 默认值:`-1`
- 范围:`[1, 256]`
-- 这个变量用来设置 IndexMerge 进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效,实际并发度为 `tidb_index_merge_intersection_concurrency` 与分区表分区数目两者中较小的值。
-- 默认值 `-1` 表示使用 `tidb_executor_concurrency` 的值。
+- 这个变量用来设置索引合并进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效。实际并发度为 `tidb_index_merge_intersection_concurrency` 与分区表分区数目两者中较小的值。
+- 默认值 `-1` 表示使用 [`tidb_executor_concurrency`](#tidb_executor_concurrency-new-in-v50) 的值。
### `tidb_index_lookup_size`
From 4a3fb50598bb0d674e095e8ef40ce36bb2400ac8 Mon Sep 17 00:00:00 2001
From: TomShawn <41534398+TomShawn@users.noreply.github.com>
Date: Thu, 1 Dec 2022 13:52:06 +0800
Subject: [PATCH 08/11] Update system-variables.md
---
system-variables.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/system-variables.md b/system-variables.md
index b52f7618d7aa..b4c08f97fc5d 100644
--- a/system-variables.md
+++ b/system-variables.md
@@ -1886,7 +1886,7 @@ v5.0 后,用户仍可以单独修改以上系统变量(会有废弃警告)
- 默认值:`-1`
- 范围:`[1, 256]`
- 这个变量用来设置索引合并进行交集操作时的最大并发度,仅在以动态裁剪模式访问分区表时有效。实际并发度为 `tidb_index_merge_intersection_concurrency` 与分区表分区数目两者中较小的值。
-- 默认值 `-1` 表示使用 [`tidb_executor_concurrency`](#tidb_executor_concurrency-new-in-v50) 的值。
+- 默认值 `-1` 表示使用 [`tidb_executor_concurrency`](#tidb_executor_concurrency-从-v50-版本开始引入) 的值。
### `tidb_index_lookup_size`
From 92331cb99e8f3a38eec3963568abb15912cf18ba Mon Sep 17 00:00:00 2001
From: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com>
Date: Thu, 1 Dec 2022 17:50:57 +0800
Subject: [PATCH 09/11] Apply suggestions from code review
Co-authored-by: Aolin
---
explain-index-merge.md | 8 ++++----
optimizer-hints.md | 5 +++--
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/explain-index-merge.md b/explain-index-merge.md
index eb2dd061be4e..2c88f2170346 100644
--- a/explain-index-merge.md
+++ b/explain-index-merge.md
@@ -26,7 +26,7 @@ CREATE TABLE t(a int, b int, c int, d int, INDEX idx_a(a), INDEX idx_b(b), INDEX
```
```sql
-EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a = 1 OR b = 1;
+EXPLAIN SELECT /*+ NO_INDEX_MERGE() */ * FROM t WHERE a = 1 OR b = 1;
+-------------------------+----------+-----------+---------------+--------------------------------------+
| id | estRows | task | access object | operator info |
+-------------------------+----------+-----------+---------------+--------------------------------------+
@@ -45,7 +45,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t) */ * FROM t WHERE a > 1 OR b > 1;
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
```
-例如,在上述示例中,过滤条件是使用 `OR` 条件连接的 `WHERE` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。
+例如,在上述示例中,过滤条件是使用 `OR` 连接的 `WHERE` 子句。在启用索引合并前,每个表只能使用一个索引,不能将 `a = 1` 下推到索引 `a`,也不能将 `b = 1` 下推到索引 `b`。当 `t` 中存在大量数据时,全表扫描的效率会很低。
对于以上查询语句,优化器选择了并集型索引合并的方式访问表。在这种访问方式下,优化器可以选择对一张表使用多个索引,并将每个索引的返回结果进行合并,生成以上两个示例中的后一个执行计划。此时的 `IndexMerge_8` 算子的 `operator info` 中的 `type: union` 表示该算子是一个并集型索引合并算子。它有三个子节点,其中 `IndexRangeScan_5` 和 `IndexRangeScan_6` 根据范围扫描得到符合条件的所有 `RowID`,再由 `TableRowIDScan_7` 算子根据这些 `RowID` 精确地读取所有满足条件的数据。
@@ -76,7 +76,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
+-------------------------------+---------+-----------+-------------------------+------------------------------------------------+
```
-在如上示例中,过滤条件是使用 `AND` 条件连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`、`idx_b` 或 `idx_c` 三个索引中的一个。
+在如上示例中,过滤条件是使用 `AND` 连接的 `WHERE` 子句。在启用索引合并前,只能选择使用 `idx_a`、`idx_b` 或 `idx_c` 三个索引中的一个。
如果三个过滤条件中的其中一个的过滤性非常好,直接选择对应的索引即可达到理想的执行效率。但如果数据分布同时满足以下三种情形,可以考虑使用交集型索引合并:
@@ -89,7 +89,7 @@ EXPLAIN SELECT /*+ USE_INDEX_MERGE(t, idx_a, idx_b, idx_c) */ * FROM t WHERE a >
> **注意:**
>
> - TiDB 的索引合并特性在 v5.4.0 及之后的版本默认开启,即 [`tidb_enable_index_merge`](/system-variables.md#tidb_enable_index_merge-从-v40-版本开始引入) 为 `ON`。
-> - 如果查询中使用了 SQL 优化器 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) ,无论 `tidb_enable_index_merge` 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) 才能开启索引合并。
+> - 如果查询中使用了 SQL 优化器 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-),无论 `tidb_enable_index_merge` 开关是否开启,都会强制使用索引合并特性。当过滤条件中有无法下推的表达式时,必须使用 Hint [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) 才能开启索引合并。
> - 如果查询有除了全表扫描以外的单索引扫描方式可以选择,优化器不会自动选择索引合并,只能通过 Hint 指定使用索引合并。
> - 索引合并目前无法在临时表上使用。
> - 交集型索引合并目前不会被优化器自动选择,必须使用 [`USE_INDEX_MERGE`](/optimizer-hints.md#use_index_merget1_name-idx1_name--idx2_name-) Hint 指定**表名和索引名**时才会被选择。
diff --git a/optimizer-hints.md b/optimizer-hints.md
index 0329fb5b6545..8889bd9ab17f 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -360,10 +360,11 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过索引合并的方式来访问指定的表。索引合并分为并集型和交集型两种类型,详情参见[用 EXPLAIN 查看索引合并的 SQL 执行计划](/explain-index-merge.md)。
-对于并集型索引合并,Hint 中的索引列表为可选参数,若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。示例如下。
-
对于交集型索引合并,索引列表是必选参数。
+对于并集型索引合并,Hint 中的索引列表为可选参数。若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。示例如下。
+
+
{{< copyable "sql" >}}
```sql
From 264bd0634769041d3ff1d7508eab4fa18d78d49b Mon Sep 17 00:00:00 2001
From: TomShawn <41534398+TomShawn@users.noreply.github.com>
Date: Mon, 5 Dec 2022 17:08:51 +0800
Subject: [PATCH 10/11] Update optimizer-hints.md
---
optimizer-hints.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/optimizer-hints.md b/optimizer-hints.md
index 8889bd9ab17f..4522d989cee5 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -364,7 +364,6 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
对于并集型索引合并,Hint 中的索引列表为可选参数。若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。示例如下。
-
{{< copyable "sql" >}}
```sql
From b7d58e6a78ff068a1e665986daddfd9bbdb4aaf2 Mon Sep 17 00:00:00 2001
From: TomShawn <41534398+TomShawn@users.noreply.github.com>
Date: Tue, 6 Dec 2022 11:37:30 +0800
Subject: [PATCH 11/11] Update optimizer-hints.md
Co-authored-by: Zhou Kunqin <25057648+time-and-fate@users.noreply.github.com>
---
optimizer-hints.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/optimizer-hints.md b/optimizer-hints.md
index 4522d989cee5..a842dd5e6ee1 100644
--- a/optimizer-hints.md
+++ b/optimizer-hints.md
@@ -360,9 +360,9 @@ SELECT /*+ READ_FROM_STORAGE(TIFLASH[t1], TIKV[t2]) */ t1.a FROM t t1, t t2 WHER
`USE_INDEX_MERGE(t1_name, idx1_name [, idx2_name ...])` 提示优化器通过索引合并的方式来访问指定的表。索引合并分为并集型和交集型两种类型,详情参见[用 EXPLAIN 查看索引合并的 SQL 执行计划](/explain-index-merge.md)。
-对于交集型索引合并,索引列表是必选参数。
+若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。
-对于并集型索引合并,Hint 中的索引列表为可选参数。若显式地指定索引列表,优化器会尝试在索引列表中选取索引来构建索引合并。若不指定索引列表,优化器会尝试在所有可用的索引中选取索引来构建索引合并。示例如下。
+对于交集型索引合并,索引列表是必选参数。对于并集型索引合并,Hint 中的索引列表为可选参数。示例如下。
{{< copyable "sql" >}}