Skip to content

Commit

Permalink
planner: refine the codes of embeded limit of double read (#42818) (#…
Browse files Browse the repository at this point in the history
…43884)

ref #24636, close #35952, close #43528
  • Loading branch information
ti-chi-bot authored May 17, 2023
1 parent 375e57b commit dd79f8e
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 67 deletions.
11 changes: 5 additions & 6 deletions cmd/explaintest/r/explain_easy.result
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,11 @@ Projection 10000.00 root eq(test.t1.c2, test.t2.c2)->Column#11
└─Apply 10000.00 root CARTESIAN left outer join
├─TableReader(Build) 10000.00 root data:TableFullScan
│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
└─Limit(Probe) 10000.00 root offset:0, count:1
└─Projection 10000.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 10000.00 root
├─Limit(Build) 10000.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 10000.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo
└─TableRowIDScan(Probe) 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─Projection(Probe) 10000.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 10000.00 root limit embedded(offset:0, count:1)
├─Limit(Build) 10000.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 10000.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo
└─TableRowIDScan(Probe) 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
explain format = 'brief' select * from t1 order by c1 desc limit 1;
id estRows task access object operator info
Limit 1.00 root offset:0, count:1
Expand Down
100 changes: 46 additions & 54 deletions planner/core/casetest/testdata/integration_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@
{
"SQL": "explain format = 'brief' select * from tbl use index(idx_b_c) where b > 1 order by b desc limit 2,1",
"Plan": [
"Limit 1.00 root offset:2, count:1",
"└─Projection 3.00 root test.tbl.a, test.tbl.b, test.tbl.c",
" └─IndexLookUp 3.00 root ",
" ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3",
" │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc",
" └─TableRowIDScan(Probe) 3.00 cop[tikv] table:tbl keep order:false"
"Projection 1.00 root test.tbl.a, test.tbl.b, test.tbl.c",
"└─IndexLookUp 1.00 root limit embedded(offset:2, count:1)",
" ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3",
" │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc",
" └─TableRowIDScan(Probe) 1.00 cop[tikv] table:tbl keep order:false"
]
},
{
Expand Down Expand Up @@ -4329,12 +4328,11 @@
{
"SQL": "explain select /*+ order_index(t1, idx_a) */ * from t1 where a<10 order by a limit 1;",
"Plan": [
"Limit_12 1.00 root offset:0, count:1",
"└─Projection_17 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_16 1.00 root ",
" ├─Limit_15(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_17 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_16 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_15(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
Expand Down Expand Up @@ -4444,48 +4442,44 @@
{
"SQL": "explain select /*+ order_index(t1, idx_a) use_index(t1, idx_a) */ * from t1 where a<10 order by a limit 1;",
"Plan": [
"Limit_12 1.00 root offset:0, count:1",
"└─Projection_19 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_18 1.00 root ",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_19 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_18 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
{
"SQL": "explain select /*+ order_index(t1, idx_a) */ * from t1 use index(idx_a) where a<10 order by a limit 1;",
"Plan": [
"Limit_12 1.00 root offset:0, count:1",
"└─Projection_19 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_18 1.00 root ",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_19 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_18 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
{
"SQL": "explain select /*+ order_index(t1, idx_a) force_index(t1, idx_a) */ * from t1 where a<10 order by a limit 1;",
"Plan": [
"Limit_12 1.00 root offset:0, count:1",
"└─Projection_19 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_18 1.00 root ",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_19 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_18 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
{
"SQL": "explain select /*+ order_index(t1, idx_a) */ * from t1 force index(idx_a) where a<10 order by a limit 1;",
"Plan": [
"Limit_12 1.00 root offset:0, count:1",
"└─Projection_19 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_18 1.00 root ",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_19 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_18 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_13 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_14(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
Expand Down Expand Up @@ -4658,12 +4652,11 @@
{
"SQL": "explain select /*+ qb_name(qb, v) order_index(t1@qb, idx_a) */ * from v",
"Plan": [
"Limit_14 1.00 root offset:0, count:1",
"└─Projection_19 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_18 1.00 root ",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_15 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_16(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
"Projection_19 1.00 root test.t1.a, test.t1.b",
"└─IndexLookUp_18 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_17(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_15 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_16(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
Expand Down Expand Up @@ -4701,20 +4694,19 @@
{
"SQL": "explain WITH CTE AS (select /*+ order_index(t1, idx_a) */ * from t1 where a<10 order by a limit 1) SELECT * FROM CTE WHERE CTE.a <18 union select * from cte where cte.b > 1;",
"Plan": [
"HashAgg_30 2.00 root group by:Column#8, Column#9, funcs:firstrow(Column#8)->Column#8, funcs:firstrow(Column#9)->Column#9",
"└─Union_31 1.28 root ",
" ├─Selection_33 0.64 root lt(test.t1.a, 18)",
" │ └─CTEFullScan_34 0.80 root CTE:cte data:CTE_0",
" └─Selection_36 0.64 root gt(test.t1.b, 1)",
" └─CTEFullScan_37 0.80 root CTE:cte data:CTE_0",
"HashAgg_31 2.00 root group by:Column#8, Column#9, funcs:firstrow(Column#8)->Column#8, funcs:firstrow(Column#9)->Column#9",
"└─Union_32 1.28 root ",
" ├─Selection_34 0.64 root lt(test.t1.a, 18)",
" │ └─CTEFullScan_35 0.80 root CTE:cte data:CTE_0",
" └─Selection_37 0.64 root gt(test.t1.b, 1)",
" └─CTEFullScan_38 0.80 root CTE:cte data:CTE_0",
"CTE_0 0.80 root Non-Recursive CTE",
"└─Selection_18(Seed Part) 0.80 root or(lt(test.t1.a, 18), gt(test.t1.b, 1))",
" └─Limit_24 1.00 root offset:0, count:1",
" └─Projection_29 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_28 1.00 root ",
" ├─Limit_27(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_25 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_26(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
" └─Projection_29 1.00 root test.t1.a, test.t1.b",
" └─IndexLookUp_28 1.00 root limit embedded(offset:0, count:1)",
" ├─Limit_27(Build) 1.00 cop[tikv] offset:0, count:1",
" │ └─IndexRangeScan_25 1.00 cop[tikv] table:t1, index:idx_a(a) range:[-inf,10), keep order:true, stats:pseudo",
" └─TableRowIDScan_26(Probe) 1.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
],
"Warn": null
},
Expand Down
21 changes: 14 additions & 7 deletions planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,20 +897,27 @@ func (p *PhysicalLimit) sinkIntoIndexLookUp(t task) bool {
}
}

// We can sink Limit into IndexLookUpReader only if tablePlan contains no Selection.
ts, isTableScan := reader.tablePlan.(*PhysicalTableScan)
if !isTableScan {
return false
}

// If this happens, some Projection Operator must be inlined into this Limit. (issues/14428)
// For example, if the original plan is `IndexLookUp(col1, col2) -> Limit(col1, col2) -> Project(col1)`,
// then after inlining the Project, it will be `IndexLookUp(col1, col2) -> Limit(col1)` here.
// If the Limit is sunk into the IndexLookUp, the IndexLookUp's schema needs to be updated as well,
// but updating it here is not safe, so do not sink Limit into this IndexLookUp in this case now.
// So we add an extra projection to solve the problem.
if p.Schema().Len() != reader.Schema().Len() {
return false
extraProj := PhysicalProjection{
Exprs: expression.Column2Exprs(p.schema.Columns),
}.Init(p.SCtx(), p.statsInfo(), p.blockOffset, nil)
extraProj.SetSchema(p.schema)
// If the root.p is already a Projection. We left the optimization for the later Projection Elimination.
extraProj.SetChildren(root.p)
root.p = extraProj
}

// We can sink Limit into IndexLookUpReader only if tablePlan contains no Selection.
ts, isTableScan := reader.tablePlan.(*PhysicalTableScan)
if !isTableScan {
return false
}
reader.PushedLimit = &PushedDownLimit{
Offset: p.Offset,
Count: p.Count,
Expand Down

0 comments on commit dd79f8e

Please sign in to comment.