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" >}}