Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: add a fix control to allow generate index merge path when normal index lookup path exists #52872

Merged
merged 7 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions pkg/planner/core/indexmerge_path.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,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"
Expand Down Expand Up @@ -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 i := 1; i < len(ds.possibleAccessPaths); i++ {
if len(ds.possibleAccessPaths[i].AccessConds) != 0 {
needConsiderIndexMerge = false
break
}
}
}
if needConsiderIndexMerge {
Expand Down
3 changes: 3 additions & 0 deletions pkg/planner/util/fixcontrol/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ 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
)

// GetStr fetches the given key from the fix control map as a string type.
Expand Down
39 changes: 39 additions & 0 deletions tests/integrationtest/r/planner/core/indexmerge_path.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
11 changes: 11 additions & 0 deletions tests/integrationtest/t/planner/core/indexmerge_path.test
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more test cases like:
b = '2' OR c = 3 OR b = '3' OR c = 4

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated~

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;