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: consider seek cost of probe-side for index join #33867

Merged
merged 44 commits into from
Apr 18, 2022
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
029b606
fixup
qw4990 Apr 10, 2022
b877ec4
fixup
qw4990 Apr 10, 2022
c070de8
fixup
qw4990 Apr 10, 2022
7f25f11
fixup
qw4990 Apr 10, 2022
4a908e0
fixup
qw4990 Apr 10, 2022
15f50f8
fixup
qw4990 Apr 10, 2022
7fe50d7
fixup
qw4990 Apr 10, 2022
a9d7b0d
fixup
qw4990 Apr 10, 2022
36d8bc0
fixup
qw4990 Apr 10, 2022
21cb413
fixup
qw4990 Apr 10, 2022
9d2b421
fixup
qw4990 Apr 10, 2022
2257464
fixup
qw4990 Apr 10, 2022
c2701d1
fixup
qw4990 Apr 11, 2022
8fa5cba
fixup
qw4990 Apr 11, 2022
c2bb472
fixup
qw4990 Apr 12, 2022
a74991f
fixup
qw4990 Apr 12, 2022
415b85d
fixup
qw4990 Apr 12, 2022
28c9163
fixup
qw4990 Apr 12, 2022
0f01ca9
Merge branch 'master' into fix-33844
qw4990 Apr 12, 2022
30915b0
fixup
qw4990 Apr 12, 2022
0c17da2
fixup
qw4990 Apr 12, 2022
be938b3
fixup
qw4990 Apr 12, 2022
88cdfd7
Merge branch 'master' into fix-33844
qw4990 Apr 12, 2022
99647ac
fixup
qw4990 Apr 12, 2022
273db42
Merge branch 'master' into fix-33844
qw4990 Apr 12, 2022
1b3cc1f
Merge branch 'master' into fix-33844
qw4990 Apr 13, 2022
8ab3a9c
Merge branch 'master' into fix-32362
qw4990 Apr 13, 2022
39ffc86
fixup
qw4990 Apr 13, 2022
d52dea4
Merge remote-tracking branch 'upstream/master' into fix-32362
qw4990 Apr 13, 2022
26eec5a
fix ci
qw4990 Apr 13, 2022
5bb3978
fix ci
qw4990 Apr 13, 2022
c6d0cf0
fix ci
qw4990 Apr 13, 2022
925200b
fix ci
qw4990 Apr 13, 2022
a817a1f
fix ci
qw4990 Apr 13, 2022
7534ae4
fix ci
qw4990 Apr 13, 2022
2e841bd
fix ci
qw4990 Apr 13, 2022
6a821e5
fix ci
qw4990 Apr 13, 2022
80abc1c
fix ci
qw4990 Apr 13, 2022
facd4aa
fix ci
qw4990 Apr 13, 2022
21c0333
fix ci
qw4990 Apr 13, 2022
8912d3d
Merge branch 'master' into fix-32362
qw4990 Apr 13, 2022
81b3197
fix ci
qw4990 Apr 13, 2022
43c8242
Merge branch 'master' into fix-32362
qw4990 Apr 18, 2022
ee75dc8
fixup
qw4990 Apr 18, 2022
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
7 changes: 3 additions & 4 deletions executor/partition_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3524,13 +3524,12 @@ func TestPartitionTableExplain(t *testing.T) {
" └─IndexReader 1.00 root index:IndexFullScan",
" └─IndexFullScan 1.00 cop[tikv] table:t, partition:P2, index:b(b) keep order:false"))
tk.MustQuery(`explain format = 'brief' select * from t partition (p1),t2 where t2.a = 1 and t2.b = t.b`).Check(testkit.Rows(
"IndexJoin 1.00 root inner join, inner:IndexReader, outer key:testpartitiontableexplain.t2.b, inner key:testpartitiontableexplain.t.b, equal cond:eq(testpartitiontableexplain.t2.b, testpartitiontableexplain.t.b)",
"HashJoin 1.00 root inner join, equal:[eq(testpartitiontableexplain.t.b, testpartitiontableexplain.t2.b)]",
"├─TableReader(Build) 1.00 root data:Selection",
"│ └─Selection 1.00 cop[tikv] eq(testpartitiontableexplain.t2.a, 1), not(isnull(testpartitiontableexplain.t2.b))",
"│ └─TableFullScan 3.00 cop[tikv] table:t2 keep order:false",
"└─IndexReader(Probe) 1.00 root index:Selection",
" └─Selection 1.00 cop[tikv] not(isnull(testpartitiontableexplain.t.b))",
" └─IndexRangeScan 1.00 cop[tikv] table:t, partition:p1, index:b(b) range: decided by [eq(testpartitiontableexplain.t.b, testpartitiontableexplain.t2.b)], keep order:false"))
"└─IndexReader(Probe) 1.00 root index:IndexFullScan",
" └─IndexFullScan 1.00 cop[tikv] table:t, partition:p1, index:b(b) keep order:false"))
tk.MustQuery(`explain format = 'brief' select * from t,t2 where t2.a = 1 and t2.b = t.b and t.a = 1`).Check(testkit.Rows(
"HashJoin 1.00 root inner join, equal:[eq(testpartitiontableexplain.t.b, testpartitiontableexplain.t2.b)]",
"├─TableReader(Build) 1.00 root data:Selection",
Expand Down
25 changes: 10 additions & 15 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,13 +773,13 @@ func (p *LogicalJoin) buildIndexJoinInner2TableScan(
if helper == nil {
return nil
}
innerTask = p.constructInnerTableScanTask(ds, nil, outerJoinKeys, us, false, false, avgInnerRowCnt)
innerTask = p.constructInnerTableScanTask(ds, helper.chosenRanges.Range(), outerJoinKeys, us, false, false, avgInnerRowCnt)
// The index merge join's inner plan is different from index join, so we
// should construct another inner plan for it.
// Because we can't keep order for union scan, if there is a union scan in inner task,
// we can't construct index merge join.
if us == nil {
innerTask2 = p.constructInnerTableScanTask(ds, nil, outerJoinKeys, us, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt)
innerTask2 = p.constructInnerTableScanTask(ds, helper.chosenRanges.Range(), outerJoinKeys, us, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt)
}
ranges = helper.chosenRanges
} else {
Expand All @@ -802,13 +802,14 @@ func (p *LogicalJoin) buildIndexJoinInner2TableScan(
if !pkMatched {
return nil
}
innerTask = p.constructInnerTableScanTask(ds, pkCol, outerJoinKeys, us, false, false, avgInnerRowCnt)
ranges := ranger.FullIntRange(mysql.HasUnsignedFlag(pkCol.RetType.Flag))
Copy link
Contributor

Choose a reason for hiding this comment

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

We change ranges here. Besides calculating seek cost of probe-side, it also affects the calculation of other costs since changing of ranges causes changing of rowCount. I'm not sure that whether helper.chosenRanges.Range() is suitable for estimating row count since it comes from (*indexJoinBuildHelper).buildTemplateRange, which seems to fill empty datum in some ranges.

Copy link
Contributor

Choose a reason for hiding this comment

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

After talking with @qw4990, ranges here only affects calculating seek cost of probe-side, it doesn't affect calculating row count or other stats. Hence it's OK.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ranges won't affect rowCount here ~
And actually, helper.chosenRanges.Range() is the only range we can use to calculate seek cost. In most cases, chosenRanges is [NULL, NULL] and len(chosenRanges) is 1, which is equal to what we use now len(FullRange). For queries like select /*+ use_index(t1, ab) */ * from t1, t2 where t1.a in (1, 2, 3) and t1.b=t2.b, it can be large than 1 and more accurate than len(FullRange).

innerTask = p.constructInnerTableScanTask(ds, ranges, outerJoinKeys, us, false, false, avgInnerRowCnt)
// The index merge join's inner plan is different from index join, so we
// should construct another inner plan for it.
// Because we can't keep order for union scan, if there is a union scan in inner task,
// we can't construct index merge join.
if us == nil {
innerTask2 = p.constructInnerTableScanTask(ds, pkCol, outerJoinKeys, us, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt)
innerTask2 = p.constructInnerTableScanTask(ds, ranges, outerJoinKeys, us, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt)
}
}
var (
Expand Down Expand Up @@ -854,7 +855,7 @@ func (p *LogicalJoin) buildIndexJoinInner2IndexScan(
maxOneRow = ok && (sf.FuncName.L == ast.EQ)
}
}
innerTask := p.constructInnerIndexScanTask(ds, helper.chosenPath, helper.chosenRemained, outerJoinKeys, us, rangeInfo, false, false, avgInnerRowCnt, maxOneRow)
innerTask := p.constructInnerIndexScanTask(ds, helper.chosenPath, helper.chosenRanges.Range(), helper.chosenRemained, outerJoinKeys, us, rangeInfo, false, false, avgInnerRowCnt, maxOneRow)
failpoint.Inject("MockOnlyEnableIndexHashJoin", func(val failpoint.Value) {
if val.(bool) {
failpoint.Return(p.constructIndexHashJoin(prop, outerIdx, innerTask, helper.chosenRanges, keyOff2IdxOff, helper.chosenPath, helper.lastColManager))
Expand All @@ -869,7 +870,7 @@ func (p *LogicalJoin) buildIndexJoinInner2IndexScan(
// Because we can't keep order for union scan, if there is a union scan in inner task,
// we can't construct index merge join.
if us == nil {
innerTask2 := p.constructInnerIndexScanTask(ds, helper.chosenPath, helper.chosenRemained, outerJoinKeys, us, rangeInfo, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt, maxOneRow)
innerTask2 := p.constructInnerIndexScanTask(ds, helper.chosenPath, helper.chosenRanges.Range(), helper.chosenRemained, outerJoinKeys, us, rangeInfo, true, !prop.IsEmpty() && prop.SortItems[0].Desc, avgInnerRowCnt, maxOneRow)
if innerTask2 != nil {
joins = append(joins, p.constructIndexMergeJoin(prop, outerIdx, innerTask2, helper.chosenRanges, keyOff2IdxOff, helper.chosenPath, helper.lastColManager)...)
}
Expand Down Expand Up @@ -925,7 +926,7 @@ func (ijHelper *indexJoinBuildHelper) buildRangeDecidedByInformation(idxCols []*
// constructInnerTableScanTask is specially used to construct the inner plan for PhysicalIndexJoin.
func (p *LogicalJoin) constructInnerTableScanTask(
ds *DataSource,
pk *expression.Column,
ranges ranger.Ranges,
outerJoinKeys []*expression.Column,
us *LogicalUnionScan,
keepOrder bool,
Expand All @@ -938,13 +939,6 @@ func (p *LogicalJoin) constructInnerTableScanTask(
if keepOrder && ds.tableInfo.GetPartitionInfo() != nil {
return nil
}
var ranges []*ranger.Range
// pk is nil means the table uses the common handle.
if pk == nil {
ranges = ranger.FullRange()
} else {
ranges = ranger.FullIntRange(mysql.HasUnsignedFlag(pk.RetType.Flag))
}
ts := PhysicalTableScan{
Table: ds.tableInfo,
Columns: ds.Columns,
Expand Down Expand Up @@ -1027,6 +1021,7 @@ func (p *LogicalJoin) constructInnerUnionScan(us *LogicalUnionScan, reader Physi
func (p *LogicalJoin) constructInnerIndexScanTask(
ds *DataSource,
path *util.AccessPath,
ranges ranger.Ranges,
filterConds []expression.Expression,
outerJoinKeys []*expression.Column,
us *LogicalUnionScan,
Expand All @@ -1052,7 +1047,7 @@ func (p *LogicalJoin) constructInnerIndexScanTask(
IdxColLens: path.IdxColLens,
dataSourceSchema: ds.schema,
KeepOrder: keepOrder,
Ranges: ranger.FullRange(),
Ranges: ranges,
rangeInfo: rangeInfo,
Desc: desc,
isPartition: ds.isPartition,
Expand Down
12 changes: 6 additions & 6 deletions planner/core/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5281,26 +5281,26 @@ func TestIndexJoinCost(t *testing.T) {
tk.MustExec(`create table t_inner_idx (a int, b int, key(a))`)

tk.MustQuery(`explain format=verbose select /*+ TIDB_INLJ(t_outer, t_inner_pk) */ * from t_outer, t_inner_pk where t_outer.a=t_inner_pk.a`).Check(testkit.Rows( // IndexJoin with inner TableScan
`IndexJoin_11 12487.50 193048.09 root inner join, inner:TableReader_8, outer key:test.t_outer.a, inner key:test.t_inner_pk.a, equal cond:eq(test.t_outer.a, test.t_inner_pk.a)`,
`IndexJoin_11 12487.50 206368.09 root inner join, inner:TableReader_8, outer key:test.t_outer.a, inner key:test.t_inner_pk.a, equal cond:eq(test.t_outer.a, test.t_inner_pk.a)`,
`├─TableReader_18(Build) 9990.00 36412.58 root data:Selection_17`,
`│ └─Selection_17 9990.00 465000.00 cop[tikv] not(isnull(test.t_outer.a))`,
`│ └─TableFullScan_16 10000.00 435000.00 cop[tikv] table:t_outer keep order:false, stats:pseudo`,
`└─TableReader_8(Probe) 1.00 2.54 root data:TableRangeScan_7`,
`└─TableReader_8(Probe) 1.00 3.88 root data:TableRangeScan_7`,
` └─TableRangeScan_7 1.00 0.00 cop[tikv] table:t_inner_pk range: decided by [test.t_outer.a], keep order:false, stats:pseudo`))
tk.MustQuery(`explain format=verbose select /*+ TIDB_INLJ(t_outer, t_inner_idx) */ t_inner_idx.a from t_outer, t_inner_idx where t_outer.a=t_inner_idx.a`).Check(testkit.Rows( // IndexJoin with inner IndexScan
`IndexJoin_10 12487.50 221872.19 root inner join, inner:IndexReader_9, outer key:test.t_outer.a, inner key:test.t_inner_idx.a, equal cond:eq(test.t_outer.a, test.t_inner_idx.a)`,
`IndexJoin_10 12487.50 235192.19 root inner join, inner:IndexReader_9, outer key:test.t_outer.a, inner key:test.t_inner_idx.a, equal cond:eq(test.t_outer.a, test.t_inner_idx.a)`,
`├─TableReader_20(Build) 9990.00 36412.58 root data:Selection_19`,
`│ └─Selection_19 9990.00 465000.00 cop[tikv] not(isnull(test.t_outer.a))`,
`│ └─TableFullScan_18 10000.00 435000.00 cop[tikv] table:t_outer keep order:false, stats:pseudo`,
`└─IndexReader_9(Probe) 1.25 4.56 root index:Selection_8`,
`└─IndexReader_9(Probe) 1.25 5.89 root index:Selection_8`,
` └─Selection_8 1.25 0.00 cop[tikv] not(isnull(test.t_inner_idx.a))`,
` └─IndexRangeScan_7 1.25 0.00 cop[tikv] table:t_inner_idx, index:a(a) range: decided by [eq(test.t_inner_idx.a, test.t_outer.a)], keep order:false, stats:pseudo`))
tk.MustQuery(`explain format=verbose select /*+ TIDB_INLJ(t_outer, t_inner_idx) */ * from t_outer, t_inner_idx where t_outer.a=t_inner_idx.a`).Check(testkit.Rows( // IndexJoin with inner IndexLookup
`IndexJoin_11 12487.50 518149.38 root inner join, inner:IndexLookUp_10, outer key:test.t_outer.a, inner key:test.t_inner_idx.a, equal cond:eq(test.t_outer.a, test.t_inner_idx.a)`,
`IndexJoin_11 12487.50 531469.38 root inner join, inner:IndexLookUp_10, outer key:test.t_outer.a, inner key:test.t_inner_idx.a, equal cond:eq(test.t_outer.a, test.t_inner_idx.a)`,
`├─TableReader_23(Build) 9990.00 36412.58 root data:Selection_22`,
`│ └─Selection_22 9990.00 465000.00 cop[tikv] not(isnull(test.t_outer.a))`,
`│ └─TableFullScan_21 10000.00 435000.00 cop[tikv] table:t_outer keep order:false, stats:pseudo`,
`└─IndexLookUp_10(Probe) 1.25 34.21 root `,
`└─IndexLookUp_10(Probe) 1.25 35.55 root `,
` ├─Selection_9(Build) 1.25 0.00 cop[tikv] not(isnull(test.t_inner_idx.a))`,
` │ └─IndexRangeScan_7 1.25 0.00 cop[tikv] table:t_inner_idx, index:a(a) range: decided by [eq(test.t_inner_idx.a, test.t_outer.a)], keep order:false, stats:pseudo`,
` └─TableRowIDScan_8(Probe) 1.25 0.00 cop[tikv] table:t_inner_idx keep order:false, stats:pseudo`))
Expand Down
16 changes: 6 additions & 10 deletions planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,7 @@ func (t *copTask) finishIndexPlan() {
for p = t.indexPlan; len(p.Children()) > 0; p = p.Children()[0] {
}
is := p.(*PhysicalIndexScan)
if !is.underInnerIndexJoin { // no need to accumulate seek cost for IndexJoin
t.cst += float64(len(is.Ranges)) * sessVars.GetSeekFactor(is.Table) // net seek cost
}
t.cst += float64(len(is.Ranges)) * sessVars.GetSeekFactor(is.Table) // net seek cost

if t.tablePlan == nil {
return
Expand Down Expand Up @@ -1077,13 +1075,11 @@ func (t *copTask) convertToRootTaskImpl(ctx sessionctx.Context) *rootTask {
ts := tp.(*PhysicalTableScan)

// net seek cost
if !ts.underInnerIndexJoin { // no need to accumulate net seek cost for IndexJoin
switch ts.StoreType {
case kv.TiKV:
t.cst += float64(len(ts.Ranges)) * sessVars.GetSeekFactor(ts.Table)
case kv.TiFlash:
t.cst += float64(len(ts.Ranges)) * float64(len(ts.Columns)) * sessVars.GetSeekFactor(ts.Table)
}
switch ts.StoreType {
case kv.TiKV:
t.cst += float64(len(ts.Ranges)) * sessVars.GetSeekFactor(ts.Table)
case kv.TiFlash:
t.cst += float64(len(ts.Ranges)) * float64(len(ts.Columns)) * sessVars.GetSeekFactor(ts.Table)
}

prevColumnLen := len(ts.Columns)
Expand Down
Loading