From 70b8cbf8a16687da7994fb07dce35e865e0f6388 Mon Sep 17 00:00:00 2001 From: time-and-fate <25057648+time-and-fate@users.noreply.github.com> Date: Wed, 24 Apr 2024 18:10:57 +0800 Subject: [PATCH 1/5] add --- pkg/planner/core/indexmerge_path.go | 16 ++++++++++++---- pkg/planner/util/fixcontrol/get.go | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/pkg/planner/core/indexmerge_path.go b/pkg/planner/core/indexmerge_path.go index 13c05e34760b6..ff113aab5b950 100644 --- a/pkg/planner/core/indexmerge_path.go +++ b/pkg/planner/core/indexmerge_path.go @@ -16,6 +16,7 @@ package core import ( "cmp" + "github.com/pingcap/tidb/pkg/planner/util/fixcontrol" "math" "slices" "strings" @@ -743,10 +744,17 @@ func (ds *DataSource) generateIndexMerge4NormalIndex(regularPathCount int, index needConsiderIndexMerge := true // if current index merge hint is nil, once there is a no-access-cond in one of possible access path. if len(ds.indexMergeHints) == 0 { - for i := 1; i < len(ds.possibleAccessPaths); i++ { - if len(ds.possibleAccessPaths[i].AccessConds) != 0 { - needConsiderIndexMerge = false - break + skipRangeScanCheck := fixcontrol.GetBoolWithDefault( + ds.SCtx().GetSessionVars().GetOptimizerFixControlMap(), + fixcontrol.Fix52869, + false, + ) + if !skipRangeScanCheck { + for _, path := range ds.possibleAccessPaths { + if len(path.AccessConds) != 0 { + needConsiderIndexMerge = false + break + } } } if needConsiderIndexMerge { diff --git a/pkg/planner/util/fixcontrol/get.go b/pkg/planner/util/fixcontrol/get.go index d7dcc38a295ca..0764bff02bdde 100644 --- a/pkg/planner/util/fixcontrol/get.go +++ b/pkg/planner/util/fixcontrol/get.go @@ -47,6 +47,7 @@ const ( // Fix49736 controls whether to force the optimizer to use plan cache even if there is risky optimization. // This fix-control is test-only. Fix49736 uint64 = 49736 + Fix52869 uint64 = 52869 ) // GetStr fetches the given key from the fix control map as a string type. From 6547c572bded6894d25fddd1b74b5c30e77d1049 Mon Sep 17 00:00:00 2001 From: time-and-fate <25057648+time-and-fate@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:36:00 +0800 Subject: [PATCH 2/5] add tests --- pkg/planner/util/fixcontrol/get.go | 2 + .../r/planner/core/indexmerge_path.result | 39 +++++++++++++++++++ .../t/planner/core/indexmerge_path.test | 11 ++++++ 3 files changed, 52 insertions(+) diff --git a/pkg/planner/util/fixcontrol/get.go b/pkg/planner/util/fixcontrol/get.go index 0764bff02bdde..6739b41f3d41b 100644 --- a/pkg/planner/util/fixcontrol/get.go +++ b/pkg/planner/util/fixcontrol/get.go @@ -47,6 +47,8 @@ const ( // Fix49736 controls whether to force the optimizer to use plan cache even if there is risky optimization. // This fix-control is test-only. Fix49736 uint64 = 49736 + // Fix52869 controls whether to disable the limitation that index merge path won't be generated automatically when + // there exist other single-index access paths that do range scan. Fix52869 uint64 = 52869 ) diff --git a/tests/integrationtest/r/planner/core/indexmerge_path.result b/tests/integrationtest/r/planner/core/indexmerge_path.result index e3dd09f1a19eb..867512871b860 100644 --- a/tests/integrationtest/r/planner/core/indexmerge_path.result +++ b/tests/integrationtest/r/planner/core/indexmerge_path.result @@ -985,3 +985,42 @@ Selection 31.95 root or(json_contains(planner__core__indexmerge_path.t1.col_45, ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t1, index:idx_17(cast(`col_45` as double array)) range:[0.5226516826882698,0.5226516826882698], keep order:false, stats:pseudo └─Selection(Probe) 26.59 cop[tikv] or(lt(planner__core__indexmerge_path.t1.col_44, 1980-03-18 00:00:00.000000), gt(planner__core__indexmerge_path.t1.col_44, 2011-10-24 00:00:00.000000)) └─TableRowIDScan 39.94 cop[tikv] table:t1 keep order:false, stats:pseudo +drop table if exists t; +create table t(pk varbinary(255) primary key, a int, b varchar(50), c int, d varchar(45), index ia(a), index ib(b), index ic(c), index id(d)); +EXPLAIN format = brief SELECT /*+ use_index_merge(t) */ * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +IndexMerge 0.03 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo +└─Selection(Probe) 0.03 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +IndexLookUp 0.03 root +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ia(a) range:[1,1], keep order:false, stats:pseudo +└─Selection(Probe) 0.03 cop[tikv] or(eq(planner__core__indexmerge_path.t.b, "2"), or(eq(planner__core__indexmerge_path.t.c, 3), eq(planner__core__indexmerge_path.t.d, "4"))) + └─TableRowIDScan 10.00 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +TableReader 9.99 root data:Selection +└─Selection 9.99 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1), or(eq(planner__core__indexmerge_path.t.b, "2"), or(eq(planner__core__indexmerge_path.t.c, 3), eq(planner__core__indexmerge_path.t.d, "4"))) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +SET @@tidb_opt_fix_control = '52869:on'; +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +IndexMerge 0.03 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo +└─Selection(Probe) 0.03 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +IndexMerge 9.99 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo +└─Selection(Probe) 9.99 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo +SET @@tidb_opt_fix_control = default; diff --git a/tests/integrationtest/t/planner/core/indexmerge_path.test b/tests/integrationtest/t/planner/core/indexmerge_path.test index 52fa5cf5cb249..059b508fb16f4 100644 --- a/tests/integrationtest/t/planner/core/indexmerge_path.test +++ b/tests/integrationtest/t/planner/core/indexmerge_path.test @@ -407,3 +407,14 @@ CREATE TABLE `t1` ( INSERT INTO t1 VALUES('1988-07-19','[0.9233398239291353, 0.9396459773262974, 0.540018481999012, 0.181978533893545]',x'652539286c5f7e6b482a7265575a'); SELECT col_44, col_45 FROM t1 WHERE NOT (col_44 BETWEEN '1980-03-18' AND '2011-10-24') GROUP BY col_46,col_45 HAVING JSON_CONTAINS(col_45, '0.540018481999012') OR JSON_OVERLAPS(col_45, '[0.5785147169732324,0.8314968898215304,0.5226516826882698]'); EXPLAIN format=brief SELECT /*+ use_index_merge(t1) */ col_44, col_45 FROM t1 WHERE NOT (col_44 BETWEEN '1980-03-18' AND '2011-10-24') GROUP BY col_46,col_45 HAVING JSON_CONTAINS(col_45, '0.540018481999012') OR JSON_OVERLAPS(col_45, '[0.5785147169732324,0.8314968898215304,0.5226516826882698]'); + +# TestIssue52869 +drop table if exists t; +create table t(pk varbinary(255) primary key, a int, b varchar(50), c int, d varchar(45), index ia(a), index ib(b), index ic(c), index id(d)); +EXPLAIN format = brief SELECT /*+ use_index_merge(t) */ * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +SET @@tidb_opt_fix_control = '52869:on'; +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +SET @@tidb_opt_fix_control = default; From ad3444f00fe57cb242aa8cb5410845146f9fe265 Mon Sep 17 00:00:00 2001 From: time-and-fate <25057648+time-and-fate@users.noreply.github.com> Date: Wed, 24 Apr 2024 19:38:48 +0800 Subject: [PATCH 3/5] fmt --- pkg/planner/core/indexmerge_path.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/planner/core/indexmerge_path.go b/pkg/planner/core/indexmerge_path.go index ff113aab5b950..b763d07128117 100644 --- a/pkg/planner/core/indexmerge_path.go +++ b/pkg/planner/core/indexmerge_path.go @@ -16,7 +16,6 @@ package core import ( "cmp" - "github.com/pingcap/tidb/pkg/planner/util/fixcontrol" "math" "slices" "strings" @@ -33,6 +32,7 @@ import ( "github.com/pingcap/tidb/pkg/planner/core/base" "github.com/pingcap/tidb/pkg/planner/util" "github.com/pingcap/tidb/pkg/planner/util/debugtrace" + "github.com/pingcap/tidb/pkg/planner/util/fixcontrol" "github.com/pingcap/tidb/pkg/statistics" "github.com/pingcap/tidb/pkg/types" "github.com/pingcap/tidb/pkg/util/chunk" From 3c34b8a7d6b843b5e216414c14f491814305cb63 Mon Sep 17 00:00:00 2001 From: time-and-fate <25057648+time-and-fate@users.noreply.github.com> Date: Wed, 24 Apr 2024 21:16:43 +0800 Subject: [PATCH 4/5] revert --- pkg/planner/core/indexmerge_path.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/planner/core/indexmerge_path.go b/pkg/planner/core/indexmerge_path.go index b763d07128117..2483e57f2c1ca 100644 --- a/pkg/planner/core/indexmerge_path.go +++ b/pkg/planner/core/indexmerge_path.go @@ -750,8 +750,8 @@ func (ds *DataSource) generateIndexMerge4NormalIndex(regularPathCount int, index false, ) if !skipRangeScanCheck { - for _, path := range ds.possibleAccessPaths { - if len(path.AccessConds) != 0 { + for i := 1; i < len(ds.possibleAccessPaths); i++ { + if len(ds.possibleAccessPaths[i].AccessConds) != 0 { needConsiderIndexMerge = false break } From 938bf30074bc0d9ab812945c4b158d918940ff43 Mon Sep 17 00:00:00 2001 From: time-and-fate <25057648+time-and-fate@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:10:22 +0800 Subject: [PATCH 5/5] add test cases --- .../r/planner/core/indexmerge_path.result | 55 +++++++++++++++++++ .../t/planner/core/indexmerge_path.test | 7 +++ 2 files changed, 62 insertions(+) diff --git a/tests/integrationtest/r/planner/core/indexmerge_path.result b/tests/integrationtest/r/planner/core/indexmerge_path.result index 867512871b860..696560821af9f 100644 --- a/tests/integrationtest/r/planner/core/indexmerge_path.result +++ b/tests/integrationtest/r/planner/core/indexmerge_path.result @@ -993,6 +993,14 @@ IndexMerge 0.03 root type: union ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo +└─Selection(Probe) 0.03 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT /*+ set_var(tidb_opt_fix_control='52869:on') */ * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +id estRows task access object operator info +IndexMerge 0.03 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo └─Selection(Probe) 0.03 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1) └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); @@ -1006,6 +1014,22 @@ id estRows task access object operator info TableReader 9.99 root data:Selection └─Selection 9.99 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1), or(eq(planner__core__indexmerge_path.t.b, "2"), or(eq(planner__core__indexmerge_path.t.c, 3), eq(planner__core__indexmerge_path.t.d, "4"))) └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5); +id estRows task access object operator info +TableReader 13.32 root data:Selection +└─Selection 13.32 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1), or(or(eq(planner__core__indexmerge_path.t.b, "2"), eq(planner__core__indexmerge_path.t.c, 3)), or(eq(planner__core__indexmerge_path.t.b, "4"), eq(planner__core__indexmerge_path.t.c, 5))) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5 OR b = '12' OR c = 13); +id estRows task access object operator info +TableReader 19.97 root data:Selection +└─Selection 19.97 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1), or(or(eq(planner__core__indexmerge_path.t.b, "2"), or(eq(planner__core__indexmerge_path.t.c, 3), eq(planner__core__indexmerge_path.t.b, "4"))), or(eq(planner__core__indexmerge_path.t.c, 5), or(eq(planner__core__indexmerge_path.t.b, "12"), eq(planner__core__indexmerge_path.t.c, 13)))) + └─TableFullScan 10000.00 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (c = 13 OR c = 15 OR c = 5 OR b = '12' OR c = 13 OR b = '11'); +id estRows task access object operator info +IndexLookUp 0.05 root +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ia(a) range:[1,1], keep order:false, stats:pseudo +└─Selection(Probe) 0.05 cop[tikv] or(or(eq(planner__core__indexmerge_path.t.c, 13), or(eq(planner__core__indexmerge_path.t.c, 15), eq(planner__core__indexmerge_path.t.c, 5))), or(eq(planner__core__indexmerge_path.t.b, "12"), or(eq(planner__core__indexmerge_path.t.c, 13), eq(planner__core__indexmerge_path.t.b, "11")))) + └─TableRowIDScan 10.00 cop[tikv] table:t keep order:false, stats:pseudo SET @@tidb_opt_fix_control = '52869:on'; EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); id estRows task access object operator info @@ -1023,4 +1047,35 @@ IndexMerge 9.99 root type: union ├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:id(d) range:["4","4"], keep order:false, stats:pseudo └─Selection(Probe) 9.99 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1) └─TableRowIDScan 29.97 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5); +id estRows task access object operator info +IndexMerge 13.32 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["4","4"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[5,5], keep order:false, stats:pseudo +└─Selection(Probe) 13.32 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 39.96 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5 OR b = '12' OR c = 13); +id estRows task access object operator info +IndexMerge 19.97 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["2","2"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[3,3], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["4","4"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[5,5], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["12","12"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[13,13], keep order:false, stats:pseudo +└─Selection(Probe) 19.97 cop[tikv] gt(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 59.91 cop[tikv] table:t keep order:false, stats:pseudo +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (c = 13 OR c = 15 OR c = 5 OR b = '12' OR c = 13 OR b = '11'); +id estRows task access object operator info +IndexMerge 0.05 root type: union +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[13,13], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[15,15], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[5,5], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["12","12"], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ic(c) range:[13,13], keep order:false, stats:pseudo +├─IndexRangeScan(Build) 10.00 cop[tikv] table:t, index:ib(b) range:["11","11"], keep order:false, stats:pseudo +└─Selection(Probe) 0.05 cop[tikv] eq(planner__core__indexmerge_path.t.a, 1) + └─TableRowIDScan 49.94 cop[tikv] table:t keep order:false, stats:pseudo SET @@tidb_opt_fix_control = default; diff --git a/tests/integrationtest/t/planner/core/indexmerge_path.test b/tests/integrationtest/t/planner/core/indexmerge_path.test index 059b508fb16f4..e398b39dba679 100644 --- a/tests/integrationtest/t/planner/core/indexmerge_path.test +++ b/tests/integrationtest/t/planner/core/indexmerge_path.test @@ -412,9 +412,16 @@ EXPLAIN format=brief SELECT /*+ use_index_merge(t1) */ col_44, col_45 FROM t1 WH drop table if exists t; create table t(pk varbinary(255) primary key, a int, b varchar(50), c int, d varchar(45), index ia(a), index ib(b), index ic(c), index id(d)); EXPLAIN format = brief SELECT /*+ use_index_merge(t) */ * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT /*+ set_var(tidb_opt_fix_control='52869:on') */ * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5 OR b = '12' OR c = 13); +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (c = 13 OR c = 15 OR c = 5 OR b = '12' OR c = 13 OR b = '11'); SET @@tidb_opt_fix_control = '52869:on'; EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (b = '2' OR c = 3 OR d = '4'); EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR d = '4'); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5); +EXPLAIN format = brief SELECT * FROM t WHERE a > 1 AND (b = '2' OR c = 3 OR b = '4' OR c = 5 OR b = '12' OR c = 13); +EXPLAIN format = brief SELECT * FROM t WHERE a = 1 AND (c = 13 OR c = 15 OR c = 5 OR b = '12' OR c = 13 OR b = '11'); SET @@tidb_opt_fix_control = default;