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: remove other accessPaths if one is unique key and full matched. #6925

Merged
merged 13 commits into from
Jun 29, 2018
11 changes: 10 additions & 1 deletion cmd/explaintest/r/explain_easy_stats.result
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ create table t2 (c1 int unique, c2 int);
load stats 's/explain_easy_stats_t2.json';
create table t3 (a bigint, b bigint, c bigint, d bigint);
load stats 's/explain_easy_stats_t3.json';
create table index_prune(a bigint(20) NOT NULL, b bigint(20) NOT NULL, c tinyint(4) NOT NULL, primary key(a, b), index idx_b_c_a(b, c, a));
load stats 's/explain_easy_stats_index_prune.json';
set @@session.tidb_opt_insubquery_unfold = 1;
set @@session.tidb_opt_agg_push_down = 1;
explain select * from t3 where exists (select s.a from t3 s having sum(s.a) = t3.a );
Expand Down Expand Up @@ -150,4 +152,11 @@ label = "cop"
"TableReader_12" -> "Selection_11"
}

drop table if exists t1, t2, t3;
explain select * from index_prune WHERE a = 1010010404050976781 AND b = 26467085526790 LIMIT 1;
id task operator info count
Limit_9 root offset:0, count:1 1.00
└─IndexLookUp_15 root index:Limit_14, table:TableScan_13 1.00
├─Limit_14 cop offset:0, count:1 1.00
│ └─IndexScan_12 cop table:index_prune, index:a, b, range:[1010010404050976781 26467085526790,1010010404050976781 26467085526790], keep order:false 1.00
└─TableScan_13 cop table:index_prune, keep order:false 1.00
drop table if exists t1, t2, t3, index_prune;
1 change: 1 addition & 0 deletions cmd/explaintest/s/explain_easy_stats_index_prune.json

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion cmd/explaintest/t/explain_easy_stats.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ create table t2 (c1 int unique, c2 int);
load stats 's/explain_easy_stats_t2.json';
create table t3 (a bigint, b bigint, c bigint, d bigint);
load stats 's/explain_easy_stats_t3.json';
create table index_prune(a bigint(20) NOT NULL, b bigint(20) NOT NULL, c tinyint(4) NOT NULL, primary key(a, b), index idx_b_c_a(b, c, a));
load stats 's/explain_easy_stats_index_prune.json';
set @@session.tidb_opt_insubquery_unfold = 1;
set @@session.tidb_opt_agg_push_down = 1;

Expand Down Expand Up @@ -45,4 +47,6 @@ explain select 1 in (select c2 from t2) from t1;
# explain format="dot" select sum(t1.c1 in (select c1 from t2)) from t1;
explain format="dot" select 1 in (select c2 from t2) from t1;

drop table if exists t1, t2, t3;
explain select * from index_prune WHERE a = 1010010404050976781 AND b = 26467085526790 LIMIT 1;

drop table if exists t1, t2, t3, index_prune;
42 changes: 32 additions & 10 deletions plan/logical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,9 @@ type accessPath struct {
forced bool
}

func (ds *DataSource) deriveTablePathStats(path *accessPath) error {
// deriveTablePathStats will fulfill the information that the accessPath need.
// And it will check whether the primary key is covered only by point query.
func (ds *DataSource) deriveTablePathStats(path *accessPath) (bool, error) {
Copy link
Member

Choose a reason for hiding this comment

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

Add comment for the newly added return value.

var err error
sc := ds.ctx.GetSessionVars().StmtCtx
path.countAfterAccess = float64(ds.statisticTable.Count)
Expand All @@ -347,11 +349,11 @@ func (ds *DataSource) deriveTablePathStats(path *accessPath) error {
}
if pkCol == nil {
path.ranges = ranger.FullIntRange(false)
return nil
return false, nil
}
path.ranges = ranger.FullIntRange(mysql.HasUnsignedFlag(pkCol.RetType.Flag))
if len(ds.pushedDownConds) == 0 {
return nil
return false, nil
}
path.accessConds, path.tableFilters = ranger.DetachCondsForTableRange(ds.ctx, ds.pushedDownConds, pkCol)
// If there's no access cond, we try to find that whether there's expression containing correlated column that
Expand Down Expand Up @@ -387,17 +389,28 @@ func (ds *DataSource) deriveTablePathStats(path *accessPath) error {
}
if corColInAccessConds {
path.countAfterAccess = 1
return nil
return true, nil
}
path.ranges, err = ranger.BuildTableRange(path.accessConds, sc, pkCol.RetType)
if err != nil {
return errors.Trace(err)
return false, errors.Trace(err)
}
path.countAfterAccess, err = ds.statisticTable.GetRowCountByIntColumnRanges(sc, pkCol.ID, path.ranges)
return errors.Trace(err)
// Check whether the primary key is covered by point query.
noIntervalRange := true
Copy link
Member

Choose a reason for hiding this comment

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

Add comments here.

Copy link
Member

Choose a reason for hiding this comment

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

how about s/noIntervalRange/allPointRanges/? This variable renaming can make code logic more clear.

Copy link
Member

Choose a reason for hiding this comment

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

Agree

Copy link
Member

Choose a reason for hiding this comment

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

s/noIntervalRange/allPointRanges/ or s/noIntervalRange/onlyPoint/

Copy link
Member Author

Choose a reason for hiding this comment

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

noIntervalRange is better. Since there may be the case that the range is empty.

Copy link
Member

Choose a reason for hiding this comment

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

Any example?

Copy link
Member Author

Choose a reason for hiding this comment

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

like a > 5 and a < 3...

Copy link
Member

Choose a reason for hiding this comment

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

ok

for _, ran := range path.ranges {
if !ran.IsPoint(sc) {
noIntervalRange = false
break
}
}
return noIntervalRange, errors.Trace(err)
}

func (ds *DataSource) deriveIndexPathStats(path *accessPath) error {
// deriveIndexPathStats will fulfill the information that the accessPath need.
// And it will check whether this index is full matched by point query. We will use this check to
// determine whether we remove other paths or not.
func (ds *DataSource) deriveIndexPathStats(path *accessPath) (bool, error) {
Copy link
Member

Choose a reason for hiding this comment

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

ditto

var err error
sc := ds.ctx.GetSessionVars().StmtCtx
path.ranges = ranger.FullRange()
Expand All @@ -406,11 +419,11 @@ func (ds *DataSource) deriveIndexPathStats(path *accessPath) error {
if len(path.idxCols) != 0 {
path.ranges, path.accessConds, path.tableFilters, path.eqCondCount, err = ranger.DetachCondAndBuildRangeForIndex(ds.ctx, ds.pushedDownConds, path.idxCols, path.idxColLens)
if err != nil {
return errors.Trace(err)
return false, errors.Trace(err)
}
path.countAfterAccess, err = ds.statisticTable.GetRowCountByIndexRanges(sc, path.index.ID, path.ranges)
if err != nil {
return errors.Trace(err)
return false, errors.Trace(err)
}
} else {
path.tableFilters = ds.pushedDownConds
Expand Down Expand Up @@ -441,7 +454,16 @@ func (ds *DataSource) deriveIndexPathStats(path *accessPath) error {
}
path.countAfterIndex = math.Max(path.countAfterAccess*selectivity, ds.statsAfterSelect.count)
}
return nil
// Check whether there's only point query.
noIntervalRanges := true
for _, ran := range path.ranges {
// Not point or the not full matched.
if !ran.IsPoint(sc) || len(ran.HighVal) != len(path.index.Columns) {
noIntervalRanges = false
break
}
}
return noIntervalRanges, nil
}

func (path *accessPath) splitCorColAccessCondFromFilters() (access, remained []expression.Expression) {
Expand Down
16 changes: 14 additions & 2 deletions plan/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,16 +128,28 @@ func (ds *DataSource) deriveStats() (*statsInfo, error) {
ds.statsAfterSelect = ds.getStatsByFilter(ds.pushedDownConds)
for _, path := range ds.possibleAccessPaths {
if path.isTablePath {
err := ds.deriveTablePathStats(path)
onlyPoint, err := ds.deriveTablePathStats(path)
if err != nil {
return nil, errors.Trace(err)
}
// If there's only point range. Just remove other possible paths.
if onlyPoint {
ds.possibleAccessPaths[0] = path
ds.possibleAccessPaths = ds.possibleAccessPaths[:1]
break
}
continue
}
err := ds.deriveIndexPathStats(path)
onlyPoint, err := ds.deriveIndexPathStats(path)
if err != nil {
return nil, errors.Trace(err)
}
// If there's only point range and this index is unique key. Just remove other possible paths.
if onlyPoint && path.index.Unique {
ds.possibleAccessPaths[0] = path
ds.possibleAccessPaths = ds.possibleAccessPaths[:1]
break
}
}
return ds.statsAfterSelect, nil
}
Expand Down
4 changes: 2 additions & 2 deletions statistics/selectivity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ func (s *testSelectivitySuite) TestPseudoSelectivity(c *C) {
testKit.MustExec("drop table if exists t, t1")
testKit.MustExec("create table t(a int, b int, unique key idx(a,b))")
testKit.MustQuery("explain select * from t where a = 1 and b = 1").Check(testkit.Rows(
"IndexReader_9 root index:IndexScan_8 1.00",
"└─IndexScan_8 cop table:t, index:a, b, range:[1 1,1 1], keep order:false 1.00"))
"IndexReader_6 root index:IndexScan_5 1.00",
"└─IndexScan_5 cop table:t, index:a, b, range:[1 1,1 1], keep order:false 1.00"))

testKit.MustExec("create table t1(a int, b int, primary key(a))")
testKit.MustQuery("explain select b from t1 where a = 1").Check(testkit.Rows(
Expand Down