Skip to content

Commit

Permalink
*: bypass order by clause for fast point get plan (#50204) (#50365)
Browse files Browse the repository at this point in the history
close #49920
  • Loading branch information
ti-chi-bot authored Feb 28, 2024
1 parent 01a5573 commit eb789e0
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 76 deletions.
4 changes: 3 additions & 1 deletion cmd/explaintest/r/explain_easy_stats.result
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,9 @@ id estRows task access object operator info
Point_Get 1.00 root table:index_prune, index:PRIMARY(a, b)
explain format = 'brief' select * from index_prune WHERE a = 1010010404050976781 AND b = 26467085526790 GROUP BY b ORDER BY a limit 1;
id estRows task access object operator info
Point_Get 1.00 root table:index_prune, index:PRIMARY(a, b)
TopN 1.00 root test.index_prune.a, offset:0, count:1
└─StreamAgg 1.00 root group by:test.index_prune.b, funcs:firstrow(test.index_prune.a)->test.index_prune.a, funcs:firstrow(test.index_prune.b)->test.index_prune.b, funcs:firstrow(test.index_prune.c)->test.index_prune.c
└─Point_Get 1.00 root table:index_prune, index:PRIMARY(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;
Expand Down
76 changes: 76 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5045,6 +5045,82 @@ func TestIsPointGet(t *testing.T) {
}
}

func TestCheckActRowsWithUnistore(t *testing.T) {
defer config.RestoreFunc()()
config.UpdateGlobal(func(conf *config.Config) {
conf.EnableCollectExecutionInfo = true
})
store := testkit.CreateMockStore(t)
// testSuite1 use default mockstore which is unistore
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_cost_model_version=2")
tk.MustExec("drop table if exists t_unistore_act_rows")
tk.MustExec("create table t_unistore_act_rows(a int, b int, index(a, b))")
tk.MustExec("insert into t_unistore_act_rows values (1, 0), (1, 0), (2, 0), (2, 1)")
tk.MustExec("analyze table t_unistore_act_rows")
tk.MustExec("set @@tidb_merge_join_concurrency= 5;")

type testStruct struct {
sql string
expected []string
}

tests := []testStruct{
{
sql: "select * from t_unistore_act_rows",
expected: []string{"4", "4"},
},
{
sql: "select * from t_unistore_act_rows where a > 1",
expected: []string{"2", "2"},
},
{
sql: "select * from t_unistore_act_rows where a > 1 and b > 0",
expected: []string{"1", "1", "2"},
},
{
sql: "select b from t_unistore_act_rows",
expected: []string{"4", "4"},
},
{
sql: "select * from t_unistore_act_rows where b > 0",
expected: []string{"1", "1", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows",
expected: []string{"1", "1", "1", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows group by a",
expected: []string{"2", "2", "2", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows group by b",
expected: []string{"2", "4", "4"},
},
{
sql: "with cte(a) as (select a from t_unistore_act_rows) select (select 1 from cte limit 1) from cte;",
expected: []string{"4", "1", "1", "1", "4", "4", "4", "4", "4"},
},
{
sql: "select a, row_number() over (partition by b) from t_unistore_act_rows;",
expected: []string{"4", "4", "4", "4", "4", "4", "4"},
},
{
sql: "select /*+ merge_join(t1, t2) */ * from t_unistore_act_rows t1 join t_unistore_act_rows t2 on t1.b = t2.b;",
expected: []string{"10", "10", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4"},
},
}

// Default RPC encoding may cause statistics explain result differ and then the test unstable.
tk.MustExec("set @@tidb_enable_chunk_rpc = on")

for _, test := range tests {
checkActRows(t, tk, test.sql, test.expected)
}
}

func TestClusteredIndexIsPointGet(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
Expand Down
75 changes: 3 additions & 72 deletions executor/explain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"testing"
"time"

"github.com/pingcap/tidb/config"
"github.com/pingcap/tidb/errno"
"github.com/pingcap/tidb/parser/auth"
plannercore "github.com/pingcap/tidb/planner/core"
Expand Down Expand Up @@ -315,80 +314,12 @@ func checkActRows(t *testing.T, tk *testkit.TestKit, sql string, expected []stri
}
}

func TestCheckActRowsWithUnistore(t *testing.T) {
defer config.RestoreFunc()()
config.UpdateGlobal(func(conf *config.Config) {
conf.EnableCollectExecutionInfo = true
})
func TestPointGetOrderby(t *testing.T) {
store := testkit.CreateMockStore(t)
// testSuite1 use default mockstore which is unistore
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("set tidb_cost_model_version=2")
tk.MustExec("drop table if exists t_unistore_act_rows")
tk.MustExec("create table t_unistore_act_rows(a int, b int, index(a, b))")
tk.MustExec("insert into t_unistore_act_rows values (1, 0), (1, 0), (2, 0), (2, 1)")
tk.MustExec("analyze table t_unistore_act_rows")
tk.MustExec("set @@tidb_merge_join_concurrency= 5;")

type testStruct struct {
sql string
expected []string
}

tests := []testStruct{
{
sql: "select * from t_unistore_act_rows",
expected: []string{"4", "4"},
},
{
sql: "select * from t_unistore_act_rows where a > 1",
expected: []string{"2", "2"},
},
{
sql: "select * from t_unistore_act_rows where a > 1 and b > 0",
expected: []string{"1", "1", "2"},
},
{
sql: "select b from t_unistore_act_rows",
expected: []string{"4", "4"},
},
{
sql: "select * from t_unistore_act_rows where b > 0",
expected: []string{"1", "1", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows",
expected: []string{"1", "1", "1", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows group by a",
expected: []string{"2", "2", "2", "4"},
},
{
sql: "select count(*) from t_unistore_act_rows group by b",
expected: []string{"2", "4", "4"},
},
{
sql: "with cte(a) as (select a from t_unistore_act_rows) select (select 1 from cte limit 1) from cte;",
expected: []string{"4", "1", "1", "1", "4", "4", "4", "4", "4"},
},
{
sql: "select a, row_number() over (partition by b) from t_unistore_act_rows;",
expected: []string{"4", "4", "4", "4", "4", "4", "4"},
},
{
sql: "select /*+ merge_join(t1, t2) */ * from t_unistore_act_rows t1 join t_unistore_act_rows t2 on t1.b = t2.b;",
expected: []string{"10", "10", "4", "4", "4", "4", "4", "4", "4", "4", "4", "4"},
},
}

// Default RPC encoding may cause statistics explain result differ and then the test unstable.
tk.MustExec("set @@tidb_enable_chunk_rpc = on")

for _, test := range tests {
checkActRows(t, tk, test.sql, test.expected)
}
tk.MustExec("create table t (i int key)")
require.Equal(t, tk.ExecToErr("select * from t where i = 1 order by j limit 10;").Error(), "[planner:1054]Unknown column 'j' in 'order clause'")
}

func TestExplainAnalyzeCTEMemoryAndDiskInfo(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions executor/historical_stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func TestRecordHistoryStatsMetaAfterAnalyze(t *testing.T) {
tk.MustExec("delete from test.t where test.t.a = 1")
err = h.DumpStatsDeltaToKV(handle.DumpAll)
require.NoError(t, err)
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta where table_id = '%d' order by create_time desc", tableInfo.Meta().ID)).Sort().Check(
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta where table_id = '%d'", tableInfo.Meta().ID)).Sort().Check(
testkit.Rows("40 20"))
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta_history where table_id = '%d' order by create_time desc limit 1", tableInfo.Meta().ID)).Sort().Check(
testkit.Rows("40 20"))
Expand All @@ -146,7 +146,7 @@ func TestRecordHistoryStatsMetaAfterAnalyze(t *testing.T) {
tk.MustExec("update test.t set test.t.b = 4 where test.t.a = 2")
err = h.DumpStatsDeltaToKV(handle.DumpAll)
require.NoError(t, err)
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta where table_id = '%d' order by create_time desc", tableInfo.Meta().ID)).Sort().Check(
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta where table_id = '%d'", tableInfo.Meta().ID)).Sort().Check(
testkit.Rows("50 20"))
tk.MustQuery(fmt.Sprintf("select modify_count, count from mysql.stats_meta_history where table_id = '%d' order by create_time desc limit 1", tableInfo.Meta().ID)).Sort().Check(
testkit.Rows("50 20"))
Expand Down
2 changes: 1 addition & 1 deletion planner/core/point_get_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,7 +1015,7 @@ func tryWhereIn2BatchPointGet(ctx sessionctx.Context, selStmt *ast.SelectStmt) *
// 3. All the columns must be public and not generated.
// 4. The condition is an access path that the range is a unique key.
func tryPointGetPlan(ctx sessionctx.Context, selStmt *ast.SelectStmt, check bool) *PointGetPlan {
if selStmt.Having != nil {
if selStmt.Having != nil || selStmt.OrderBy != nil {
return nil
} else if selStmt.Limit != nil {
count, offset, err := extractLimitCountOffset(ctx, selStmt.Limit)
Expand Down

0 comments on commit eb789e0

Please sign in to comment.