Skip to content

Commit

Permalink
planner: fix index merge shouldn't push partial limit down when index…
Browse files Browse the repository at this point in the history
… plans are keep ordered (pingcap#52979)

close pingcap#52947
  • Loading branch information
AilinKid authored and RidRisR committed May 23, 2024
1 parent 9c32607 commit f4e1842
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
12 changes: 9 additions & 3 deletions pkg/planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,10 +674,12 @@ func (p *PhysicalLimit) Attach2Task(tasks ...base.Task) base.Task {
} else if !cop.idxMergeIsIntersection {
// We only support push part of the order prop down to index merge build case.
if len(cop.rootTaskConds) == 0 {
if cop.indexPlanFinished {
// when the index plan is finished, sink the limit to the index merge table side.
// For double read which requires order being kept, the limit cannot be pushed down to the table side,
// because handles would be reordered before being sent to table scan.
if cop.indexPlanFinished && !cop.keepOrder {
// when the index plan is finished and index plan is not ordered, sink the limit to the index merge table side.
suspendLimitAboveTablePlan()
} else {
} else if !cop.indexPlanFinished {
// cop.indexPlanFinished = false indicates the table side is a pure table-scan, sink the limit to the index merge index side.
newCount := p.Offset + p.Count
limitChildren := make([]base.PhysicalPlan, 0, len(cop.idxMergePartPlans))
Expand All @@ -692,6 +694,10 @@ func (p *PhysicalLimit) Attach2Task(tasks ...base.Task) base.Task {
cop.idxMergePartPlans = limitChildren
t = cop.ConvertToRootTask(p.SCtx())
sunk = p.sinkIntoIndexMerge(t)
} else {
// when there are some limitations, just sink the limit upon the index merge reader.
t = cop.ConvertToRootTask(p.SCtx())
sunk = p.sinkIntoIndexMerge(t)
}
} else {
// when there are some root conditions, just sink the limit upon the index merge reader.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3728,3 +3728,44 @@ IndexMerge_20 1.00 root type: union, limit embedded(offset:0, count:1)
└─TableRowIDScan_13(Probe) 1.00 cop[tikv] table:t3 keep order:false, stats:pseudo
show warnings;
Level Code Message
CREATE TABLE `tbl_43` (
`col_304` binary(207) NOT NULL DEFAULT 'eIenHx\0\0\0\0\0\0\0\0\0\0\0\0',
PRIMARY KEY (`col_304`) /*T![clustered_index] CLUSTERED */,
UNIQUE KEY `idx_259` (`col_304`(5)),
UNIQUE KEY `idx_260` (`col_304`(2)),
KEY `idx_261` (`col_304`),
UNIQUE KEY `idx_262` (`col_304`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
insert into tbl_43 values("BCmuENPHzSOIMJLPB"),("LDOdXZYpOR"),("R"),("TloTqcHhdgpwvMsSoJ"),("UajN"),("mAwLZbiyq"),("swLIoWa");
explain format = 'brief' select min(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
id estRows task access object operator info
StreamAgg 1.00 root funcs:min(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304)->Column#2
└─Limit 1.00 root offset:0, count:1
└─IndexMerge 1.00 root type: union
├─Selection(Build) 0.00 cop[tikv] 1
│ └─TableRangeScan 0.00 cop[tikv] table:tbl_43 range:["LUBGzGMA","LUBGzGMA"], keep order:true, stats:pseudo
├─IndexRangeScan(Build) 0.42 cop[tikv] table:tbl_43, index:idx_261(col_304) range:[-inf,"YEpfYfPVvhMlHGHSMKm"), keep order:true, stats:pseudo
├─IndexRangeScan(Build) 0.42 cop[tikv] table:tbl_43, index:idx_262(col_304) range:("PE",+inf], keep order:true, stats:pseudo
├─TableRangeScan(Build) 0.42 cop[tikv] table:tbl_43 range:[-inf,"MFWmuOsoyDv"), keep order:true, stats:pseudo
├─TableRangeScan(Build) 0.42 cop[tikv] table:tbl_43 range:("TSeMYpDXnFIyp",+inf], keep order:true, stats:pseudo
└─Selection(Probe) 1.00 cop[tikv] or(or(lt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "YEpfYfPVvhMlHGHSMKm"), gt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "PE")), or(and(eq(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "LUBGzGMA"), 1), or(lt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "MFWmuOsoyDv"), gt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "TSeMYpDXnFIyp"))))
└─TableRowIDScan 1.25 cop[tikv] table:tbl_43 keep order:false, stats:pseudo
select min(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
min(col_304)
BCmuENPHzSOIMJLPB
explain format = 'brief' select max(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
id estRows task access object operator info
StreamAgg 1.00 root funcs:max(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304)->Column#2
└─Limit 1.00 root offset:0, count:1
└─IndexMerge 1.00 root type: union
├─Selection(Build) 0.00 cop[tikv] 1
│ └─TableRangeScan 0.00 cop[tikv] table:tbl_43 range:["LUBGzGMA","LUBGzGMA"], keep order:true, desc, stats:pseudo
├─IndexRangeScan(Build) 0.42 cop[tikv] table:tbl_43, index:idx_261(col_304) range:[-inf,"YEpfYfPVvhMlHGHSMKm"), keep order:true, desc, stats:pseudo
├─IndexRangeScan(Build) 0.42 cop[tikv] table:tbl_43, index:idx_262(col_304) range:("PE",+inf], keep order:true, desc, stats:pseudo
├─TableRangeScan(Build) 0.42 cop[tikv] table:tbl_43 range:[-inf,"MFWmuOsoyDv"), keep order:true, desc, stats:pseudo
├─TableRangeScan(Build) 0.42 cop[tikv] table:tbl_43 range:("TSeMYpDXnFIyp",+inf], keep order:true, desc, stats:pseudo
└─Selection(Probe) 1.00 cop[tikv] or(or(lt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "YEpfYfPVvhMlHGHSMKm"), gt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "PE")), or(and(eq(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "LUBGzGMA"), 1), or(lt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "MFWmuOsoyDv"), gt(planner__core__casetest__physicalplantest__physical_plan.tbl_43.col_304, "TSeMYpDXnFIyp"))))
└─TableRowIDScan 1.25 cop[tikv] table:tbl_43 keep order:false, stats:pseudo
select max(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
max(col_304)
swLIoWa
Original file line number Diff line number Diff line change
Expand Up @@ -992,3 +992,17 @@ set tidb_cost_model_version=DEFAULT;
explain select /*+ USE_INDEX_MERGE(t3, aid_c1, aid_c2) */ * from t3 where (aid = 1 and c1='aaa') or (aid = 1 and c2='bbb') limit 1;
show warnings;

# TestIndexMergeIssue52947
CREATE TABLE `tbl_43` (
`col_304` binary(207) NOT NULL DEFAULT 'eIenHx\0\0\0\0\0\0\0\0\0\0\0\0',
PRIMARY KEY (`col_304`) /*T![clustered_index] CLUSTERED */,
UNIQUE KEY `idx_259` (`col_304`(5)),
UNIQUE KEY `idx_260` (`col_304`(2)),
KEY `idx_261` (`col_304`),
UNIQUE KEY `idx_262` (`col_304`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
insert into tbl_43 values("BCmuENPHzSOIMJLPB"),("LDOdXZYpOR"),("R"),("TloTqcHhdgpwvMsSoJ"),("UajN"),("mAwLZbiyq"),("swLIoWa");
explain format = 'brief' select min(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
select min(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
explain format = 'brief' select max(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;
select max(col_304) from (select /*+ use_index_merge( tbl_43 ) */ * from tbl_43 where not( tbl_43.col_304 between 'YEpfYfPVvhMlHGHSMKm' and 'PE' ) or tbl_43.col_304 in ( 'LUBGzGMA' ) and tbl_43.col_304 between 'HpsjfuSReCwBoh' and 'fta' or not( tbl_43.col_304 between 'MFWmuOsoyDv' and 'TSeMYpDXnFIyp' ) order by col_304) x;

0 comments on commit f4e1842

Please sign in to comment.