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

plan: handle DNF expressions in Selectivity #9282

Merged
merged 8 commits into from
Feb 13, 2019
Merged
Show file tree
Hide file tree
Changes from 2 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
7 changes: 7 additions & 0 deletions cmd/explaintest/r/explain_easy_stats.result
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,10 @@ id count task operator info
Point_Get_1 1.00 root table:index_prune, index:a b
drop table if exists t1, t2, t3, index_prune;
set @@session.tidb_opt_insubq_to_join_and_agg=1;
drop table if exists tbl;
create table tbl(column1 int, column2 int, index idx(column1, column2));
load stats 's/explain_easy_stats_tbl_dnf.json';
explain select * from tbl where (column1=0 and column2=1) or (column1=1 and column2=3) or (column1=2 and column2=5);
id count task operator info
IndexReader_9 3.00 root index:IndexScan_8
└─IndexScan_8 3.00 cop table:tbl, index:column1, column2, range:[0 1,0 1], [1 3,1 3], [2 5,2 5], keep order:false
1 change: 1 addition & 0 deletions cmd/explaintest/s/explain_easy_stats_tbl_dnf.json

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions cmd/explaintest/t/explain_easy_stats.test
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,8 @@ explain select * from index_prune WHERE a = 1010010404050976781 AND b = 26467085

drop table if exists t1, t2, t3, index_prune;
set @@session.tidb_opt_insubq_to_join_and_agg=1;

drop table if exists tbl;
create table tbl(column1 int, column2 int, index idx(column1, column2));
load stats 's/explain_easy_stats_tbl_dnf.json';
explain select * from tbl where (column1=0 and column2=1) or (column1=1 and column2=3) or (column1=2 and column2=5);
2 changes: 1 addition & 1 deletion planner/core/common_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ func (e *Execute) buildRangeForIndexScan(sctx sessionctx.Context, is *PhysicalIn
ranges := ranger.FullRange()
if len(idxCols) > 0 {
var err error
ranges, _, _, _, err = ranger.DetachCondAndBuildRangeForIndex(sctx, is.AccessCondition, idxCols, colLengths)
ranges, _, _, _, _, err = ranger.DetachCondAndBuildRangeForIndex(sctx, is.AccessCondition, idxCols, colLengths)
if err != nil {
return nil, errors.Trace(err)
}
Expand Down
2 changes: 1 addition & 1 deletion planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ func (p *LogicalJoin) buildRangeForIndexJoin(indexInfo *model.IndexInfo, innerPl
// In `buildFakeEqCondsForIndexJoin`, we construct the equal conditions for join keys and remove filters that contain the join keys' column.
// When t1.a = t2.a and t1.a > 1, we can also guarantee that t1.a > 1 won't be chosen as the access condition.
// So the equal conditions we built can be successfully used to build a range if they can be used. They won't be affected by the existing filters.
ranges, accesses, moreRemained, _, err := ranger.DetachCondAndBuildRangeForIndex(p.ctx, access, idxCols, colLengths)
ranges, accesses, moreRemained, _, _, err := ranger.DetachCondAndBuildRangeForIndex(p.ctx, access, idxCols, colLengths)
if err != nil {
terror.Log(errors.Trace(err))
return nil, nil, nil
Expand Down
2 changes: 1 addition & 1 deletion planner/core/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ func (ds *DataSource) deriveIndexPathStats(path *accessPath) (bool, error) {
path.countAfterAccess = float64(ds.statisticTable.Count)
path.idxCols, path.idxColLens = expression.IndexInfo2Cols(ds.schema.Columns, path.index)
if len(path.idxCols) != 0 {
path.ranges, path.accessConds, path.tableFilters, path.eqCondCount, err = ranger.DetachCondAndBuildRangeForIndex(ds.ctx, ds.pushedDownConds, path.idxCols, path.idxColLens)
path.ranges, path.accessConds, path.tableFilters, path.eqCondCount, _, err = ranger.DetachCondAndBuildRangeForIndex(ds.ctx, ds.pushedDownConds, path.idxCols, path.idxColLens)
if err != nil {
return false, errors.Trace(err)
}
Expand Down
9 changes: 7 additions & 2 deletions statistics/selectivity.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,24 @@ func (coll *HistColl) Selectivity(ctx sessionctx.Context, exprs []expression.Exp
func getMaskAndRanges(ctx sessionctx.Context, exprs []expression.Expression, rangeType ranger.RangeType,
lengths []int, cols ...*expression.Column) (mask int64, ranges []*ranger.Range, err error) {
sc := ctx.GetSessionVars().StmtCtx
var accessConds []expression.Expression
isDNF := false
var accessConds, filter []expression.Expression
switch rangeType {
case ranger.ColumnRangeType:
accessConds = ranger.ExtractAccessConditionsForColumn(exprs, cols[0].UniqueID)
ranges, err = ranger.BuildColumnRange(accessConds, sc, cols[0].RetType)
case ranger.IndexRangeType:
ranges, accessConds, err = ranger.DetachSimpleCondAndBuildRangeForIndex(ctx, exprs, cols, lengths)
ranges, accessConds, filter, _, isDNF, err = ranger.DetachCondAndBuildRangeForIndex(ctx, exprs, cols, lengths)
default:
panic("should never be here")
}
if err != nil {
return 0, nil, errors.Trace(err)
}
if isDNF && len(filter) == 0 {
mask |= 1
return mask, ranges, nil
}
for i := range exprs {
for j := range accessConds {
if exprs[i].Equal(ctx, accessConds[j]) {
Expand Down
14 changes: 7 additions & 7 deletions util/ranger/detacher.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,9 @@ func detachDNFCondAndBuildRangeForIndex(sctx sessionctx.Context, condition *expr
}

// DetachCondAndBuildRangeForIndex will detach the index filters from table filters.
// If the top layer is DNF, we return a int slice which is eqAndInCount of every DNF item.
// Otherwise just one number is returned.
// If the top layer is CNF, we return a int of eqAndInCount, otherwise we return 0.
eurekaka marked this conversation as resolved.
Show resolved Hide resolved
func DetachCondAndBuildRangeForIndex(sctx sessionctx.Context, conditions []expression.Expression, cols []*expression.Column,
lengths []int) ([]*Range, []expression.Expression, []expression.Expression, int, error) {
lengths []int) (ranges []*Range, accesses, filters []expression.Expression, eqCount int, isDNF bool, err error) {
eurekaka marked this conversation as resolved.
Show resolved Hide resolved
newTpSlice := make([]*types.FieldType, 0, len(cols))
for _, col := range cols {
newTpSlice = append(newTpSlice, newFieldType(col.RetType))
Expand All @@ -310,16 +309,17 @@ func DetachCondAndBuildRangeForIndex(sctx sessionctx.Context, conditions []expre
if sf, ok := conditions[0].(*expression.ScalarFunction); ok && sf.FuncName.L == ast.LogicOr {
ranges, accesses, hasResidual, err := detachDNFCondAndBuildRangeForIndex(sctx, sf, cols, newTpSlice, lengths)
if err != nil {
return nil, nil, nil, 0, errors.Trace(err)
return nil, nil, nil, 0, false, errors.Trace(err)
}
// If this DNF have something cannot be to calculate range, then all this DNF should be pushed as filter condition.
if hasResidual {
return ranges, accesses, conditions, 0, nil
return ranges, accesses, conditions, 0, true, nil
}
return ranges, accesses, nil, 0, nil
return ranges, accesses, nil, 0, true, nil
}
}
return detachCNFCondAndBuildRangeForIndex(sctx, conditions, cols, newTpSlice, lengths, true)
ranges, accesses, filters, eqCount, err = detachCNFCondAndBuildRangeForIndex(sctx, conditions, cols, newTpSlice, lengths, true)
return ranges, accesses, filters, eqCount, false, err
}

// DetachSimpleCondAndBuildRangeForIndex will detach the index filters from table filters.
Expand Down
4 changes: 2 additions & 2 deletions util/ranger/ranger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ func (s *testRangerSuite) TestIndexRange(c *C) {
}
cols, lengths := expression.IndexInfo2Cols(selection.Schema().Columns, tbl.Indices[tt.indexPos])
c.Assert(cols, NotNil)
ranges, conds, filter, _, err := ranger.DetachCondAndBuildRangeForIndex(ctx, conds, cols, lengths)
ranges, conds, filter, _, _, err := ranger.DetachCondAndBuildRangeForIndex(ctx, conds, cols, lengths)
c.Assert(err, IsNil)
c.Assert(fmt.Sprintf("%s", conds), Equals, tt.accessConds, Commentf("wrong access conditions for expr: %s", tt.exprStr))
c.Assert(fmt.Sprintf("%s", filter), Equals, tt.filterConds, Commentf("wrong filter conditions for expr: %s", tt.exprStr))
Expand Down Expand Up @@ -681,7 +681,7 @@ func (s *testRangerSuite) TestIndexRangeForUnsignedInt(c *C) {
}
cols, lengths := expression.IndexInfo2Cols(selection.Schema().Columns, tbl.Indices[tt.indexPos])
c.Assert(cols, NotNil)
ranges, conds, filter, _, err := ranger.DetachCondAndBuildRangeForIndex(ctx, conds, cols, lengths)
ranges, conds, filter, _, _, err := ranger.DetachCondAndBuildRangeForIndex(ctx, conds, cols, lengths)
c.Assert(err, IsNil)
c.Assert(fmt.Sprintf("%s", conds), Equals, tt.accessConds, Commentf("wrong access conditions for expr: %s", tt.exprStr))
c.Assert(fmt.Sprintf("%s", filter), Equals, tt.filterConds, Commentf("wrong filter conditions for expr: %s", tt.exprStr))
Expand Down