Skip to content

Commit 5301602

Browse files
authored
planner: correct plan when scan tidb related cluster table with KeepOrder (#51922)
close #51723
1 parent 0da20ee commit 5301602

File tree

4 files changed

+138
-1
lines changed

4 files changed

+138
-1
lines changed

pkg/planner/core/find_best_task.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,10 @@ func compareCandidates(sctx base.PlanContext, statsTbl *statistics.Table, prop *
785785
}
786786

787787
func isMatchProp(ds *logicalop.DataSource, path *util.AccessPath, prop *property.PhysicalProperty) bool {
788+
if ds.Table.Type().IsClusterTable() && !prop.IsSortItemEmpty() {
789+
// TableScan with cluster table can't keep order.
790+
return false
791+
}
788792
if prop.VectorProp.VSInfo != nil && path.Index != nil && path.Index.VectorInfo != nil {
789793
if path.Index == nil || path.Index.VectorInfo == nil {
790794
return false

pkg/planner/core/task.go

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/pingcap/failpoint"
2222
"github.com/pingcap/tidb/pkg/expression"
2323
"github.com/pingcap/tidb/pkg/expression/aggregation"
24+
"github.com/pingcap/tidb/pkg/infoschema"
2425
"github.com/pingcap/tidb/pkg/kv"
2526
"github.com/pingcap/tidb/pkg/parser/ast"
2627
"github.com/pingcap/tidb/pkg/parser/charset"
@@ -1087,14 +1088,88 @@ func (p *PhysicalTopN) canPushDownToTiFlash(mppTask *MppTask) bool {
10871088
return true
10881089
}
10891090

1090-
// Attach2Task implements physical plan
1091+
// For https://github.com/pingcap/tidb/issues/51723,
1092+
// This function only supports `CLUSTER_SLOW_QUERY`,
1093+
// it will change plan from
1094+
// TopN -> TableReader -> TableFullScan[cop] to
1095+
// TopN -> TableReader -> Limit[cop] -> TableFullScan[cop] + keepOrder
1096+
func (p *PhysicalTopN) pushLimitDownToTiDBCop(copTsk *CopTask) (base.Task, bool) {
1097+
if copTsk.indexPlan != nil || copTsk.tablePlan == nil {
1098+
return nil, false
1099+
}
1100+
1101+
var (
1102+
selOnTblScan *PhysicalSelection
1103+
selSelectivity float64
1104+
tblScan *PhysicalTableScan
1105+
err error
1106+
ok bool
1107+
)
1108+
1109+
copTsk.tablePlan, err = copTsk.tablePlan.Clone(p.SCtx())
1110+
if err != nil {
1111+
return nil, false
1112+
}
1113+
finalTblScanPlan := copTsk.tablePlan
1114+
for len(finalTblScanPlan.Children()) > 0 {
1115+
selOnTblScan, _ = finalTblScanPlan.(*PhysicalSelection)
1116+
finalTblScanPlan = finalTblScanPlan.Children()[0]
1117+
}
1118+
1119+
if tblScan, ok = finalTblScanPlan.(*PhysicalTableScan); !ok {
1120+
return nil, false
1121+
}
1122+
1123+
// Check the table is `CLUSTER_SLOW_QUERY` or not.
1124+
if tblScan.Table.Name.O != infoschema.ClusterTableSlowLog {
1125+
return nil, false
1126+
}
1127+
1128+
colsProp, ok := GetPropByOrderByItems(p.ByItems)
1129+
if !ok {
1130+
return nil, false
1131+
}
1132+
if len(colsProp.SortItems) != 1 || !colsProp.SortItems[0].Col.Equal(p.SCtx().GetExprCtx().GetEvalCtx(), tblScan.HandleCols.GetCol(0)) {
1133+
return nil, false
1134+
}
1135+
if selOnTblScan != nil && tblScan.StatsInfo().RowCount > 0 {
1136+
selSelectivity = selOnTblScan.StatsInfo().RowCount / tblScan.StatsInfo().RowCount
1137+
}
1138+
tblScan.Desc = colsProp.SortItems[0].Desc
1139+
tblScan.KeepOrder = true
1140+
1141+
childProfile := copTsk.Plan().StatsInfo()
1142+
newCount := p.Offset + p.Count
1143+
stats := util.DeriveLimitStats(childProfile, float64(newCount))
1144+
pushedLimit := PhysicalLimit{
1145+
Count: newCount,
1146+
}.Init(p.SCtx(), stats, p.QueryBlockOffset())
1147+
pushedLimit.SetSchema(copTsk.tablePlan.Schema())
1148+
copTsk = attachPlan2Task(pushedLimit, copTsk).(*CopTask)
1149+
child := pushedLimit.Children()[0]
1150+
child.SetStats(child.StatsInfo().ScaleByExpectCnt(float64(newCount)))
1151+
if selSelectivity > 0 && selSelectivity < 1 {
1152+
scaledRowCount := child.StatsInfo().RowCount / selSelectivity
1153+
tblScan.SetStats(tblScan.StatsInfo().ScaleByExpectCnt(scaledRowCount))
1154+
}
1155+
rootTask := copTsk.ConvertToRootTask(p.SCtx())
1156+
return attachPlan2Task(p, rootTask), true
1157+
}
1158+
1159+
// Attach2Task implements the PhysicalPlan interface.
10911160
func (p *PhysicalTopN) Attach2Task(tasks ...base.Task) base.Task {
10921161
t := tasks[0].Copy()
10931162
cols := make([]*expression.Column, 0, len(p.ByItems))
10941163
for _, item := range p.ByItems {
10951164
cols = append(cols, expression.ExtractColumns(item.Expr)...)
10961165
}
10971166
needPushDown := len(cols) > 0
1167+
if copTask, ok := t.(*CopTask); ok && needPushDown && copTask.getStoreType() == kv.TiDB && len(copTask.rootTaskConds) == 0 {
1168+
newTask, changed := p.pushLimitDownToTiDBCop(copTask)
1169+
if changed {
1170+
return newTask
1171+
}
1172+
}
10981173
if copTask, ok := t.(*CopTask); ok && needPushDown && p.canPushDownToTiKV(copTask) && len(copTask.rootTaskConds) == 0 {
10991174
// If all columns in topN are from index plan, we push it to index plan, otherwise we finish the index plan and
11001175
// push it to table plan.

tests/integrationtest/r/infoschema/cluster_tables.result

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,51 @@ select /*+ ignore_index(t, a) */ * from t where a = 1;
1010
id a
1111
create session binding from history using plan digest '20cf414ff6bd6fff3de17a266966020e81099b9fd1a29c4fd4b8aaf212f5c2c0';
1212
drop binding for sql digest '83de0854921816c038565229b8008f5d679d373d16bf6b2a5cacd5937e11ea21';
13+
explain select * from information_schema.cluster_slow_query order by time limit 1;
14+
id estRows task access object operator info
15+
TopN_7 1.00 root information_schema.cluster_slow_query.time, offset:0, count:1
16+
└─TableReader_16 1.00 root data:Limit_15
17+
└─Limit_15 1.00 cop[tidb] offset:0, count:1
18+
└─MemTableScan_14 1.00 cop[tidb] table:CLUSTER_SLOW_QUERY
19+
explain select * from information_schema.cluster_slow_query order by time;
20+
id estRows task access object operator info
21+
Sort_4 10000.00 root information_schema.cluster_slow_query.time
22+
└─TableReader_8 10000.00 root data:MemTableScan_7
23+
└─MemTableScan_7 10000.00 cop[tidb] table:CLUSTER_SLOW_QUERY
24+
explain select * from information_schema.cluster_slow_query order by time desc limit 1;
25+
id estRows task access object operator info
26+
TopN_7 1.00 root information_schema.cluster_slow_query.time:desc, offset:0, count:1
27+
└─TableReader_16 1.00 root data:Limit_15
28+
└─Limit_15 1.00 cop[tidb] offset:0, count:1
29+
└─MemTableScan_14 1.00 cop[tidb] table:CLUSTER_SLOW_QUERY
30+
explain select * from information_schema.cluster_slow_query order by time desc;
31+
id estRows task access object operator info
32+
Sort_4 10000.00 root information_schema.cluster_slow_query.time:desc
33+
└─TableReader_8 10000.00 root data:MemTableScan_7
34+
└─MemTableScan_7 10000.00 cop[tidb] table:CLUSTER_SLOW_QUERY
35+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time limit 1;
36+
id estRows task access object operator info
37+
TopN_8 1.00 root information_schema.cluster_slow_query.time, offset:0, count:1
38+
└─TableReader_18 1.00 root data:Limit_17
39+
└─Limit_17 1.00 cop[tidb] offset:0, count:1
40+
└─Selection_16 1.00 cop[tidb] ne(information_schema.cluster_slow_query.query, "x")
41+
└─MemTableScan_15 1.50 cop[tidb] table:CLUSTER_SLOW_QUERY
42+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time;
43+
id estRows task access object operator info
44+
Sort_5 166.42 root information_schema.cluster_slow_query.time
45+
└─TableReader_10 166.42 root data:Selection_9
46+
└─Selection_9 166.42 cop[tidb] ne(information_schema.cluster_slow_query.query, "x")
47+
└─MemTableScan_8 250.00 cop[tidb] table:CLUSTER_SLOW_QUERY
48+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time desc limit 1;
49+
id estRows task access object operator info
50+
TopN_8 1.00 root information_schema.cluster_slow_query.time:desc, offset:0, count:1
51+
└─TableReader_18 1.00 root data:Limit_17
52+
└─Limit_17 1.00 cop[tidb] offset:0, count:1
53+
└─Selection_16 1.00 cop[tidb] ne(information_schema.cluster_slow_query.query, "x")
54+
└─MemTableScan_15 1.50 cop[tidb] table:CLUSTER_SLOW_QUERY
55+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time desc;
56+
id estRows task access object operator info
57+
Sort_5 166.42 root information_schema.cluster_slow_query.time:desc
58+
└─TableReader_10 166.42 root data:Selection_9
59+
└─Selection_9 166.42 cop[tidb] ne(information_schema.cluster_slow_query.query, "x")
60+
└─MemTableScan_8 250.00 cop[tidb] table:CLUSTER_SLOW_QUERY

tests/integrationtest/t/infoschema/cluster_tables.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,13 @@ select /*+ ignore_index(t, a) */ * from t where a = 1;
1010
create session binding from history using plan digest '20cf414ff6bd6fff3de17a266966020e81099b9fd1a29c4fd4b8aaf212f5c2c0';
1111
drop binding for sql digest '83de0854921816c038565229b8008f5d679d373d16bf6b2a5cacd5937e11ea21';
1212

13+
# TestIssue51723
14+
explain select * from information_schema.cluster_slow_query order by time limit 1;
15+
explain select * from information_schema.cluster_slow_query order by time;
16+
explain select * from information_schema.cluster_slow_query order by time desc limit 1;
17+
explain select * from information_schema.cluster_slow_query order by time desc;
18+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time limit 1;
19+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time;
20+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time desc limit 1;
21+
explain select * from information_schema.cluster_slow_query WHERE (time between '2020-09-24 15:23:41.421396' and '2020-09-25 17:57:35.047111') and query != 'x' order by time desc;
22+

0 commit comments

Comments
 (0)