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

*: support JSON format output in explain statement #39253

Merged
merged 38 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8fb5561
Update common_plans.go
fzzf678 Nov 17, 2022
82c74ce
uodo
fzzf678 Nov 17, 2022
5d6b829
Update common_plans.go
fzzf678 Nov 19, 2022
b810c51
happy linter
fzzf678 Nov 20, 2022
f838320
linter happy
fzzf678 Nov 20, 2022
a0bdbcb
ut
fzzf678 Nov 20, 2022
820ce56
Merge branch 'master' into explain
fzzf678 Nov 20, 2022
80b4fba
Merge branch 'explain' of https://github.com/fzzf678/tidb into explain
fzzf678 Nov 20, 2022
9bbb5c0
ut and linter
fzzf678 Nov 20, 2022
b7798c0
rename
fzzf678 Nov 20, 2022
98ed33f
Update common_plans.go
fzzf678 Nov 21, 2022
d9e3c24
linter
fzzf678 Nov 21, 2022
7deafcb
update
fzzf678 Nov 21, 2022
16f4163
fix
fzzf678 Nov 22, 2022
f7b9254
Merge branch 'master' into explain
fzzf678 Nov 22, 2022
501d6be
Update common_plans.go
fzzf678 Nov 24, 2022
057f809
nested output
fzzf678 Nov 25, 2022
80dfea8
Update common_plans.go
fzzf678 Nov 25, 2022
4fe7940
test
fzzf678 Nov 25, 2022
45e5de4
rename
fzzf678 Nov 25, 2022
381a5f1
Update common_plans.go
fzzf678 Nov 25, 2022
0a9e840
fided
fzzf678 Nov 29, 2022
c17c754
fix
fzzf678 Nov 29, 2022
6d39f5e
Merge branch 'master' into explain
fzzf678 Nov 29, 2022
bb8d7b0
Update json_plan_suite_out.json
fzzf678 Nov 29, 2022
374046c
Merge branch 'master' into explain
fzzf678 Nov 29, 2022
f22d24f
Merge branch 'master' into explain
fzzf678 Nov 29, 2022
f46dcb5
Merge branch 'master' into explain
fzzf678 Nov 29, 2022
faf920c
Merge remote-tracking branch 'upstream/master' into explain
fzzf678 Nov 30, 2022
f5dba3a
TIDB_JSON
fzzf678 Nov 30, 2022
2141b88
Merge branch 'master' into explain
fzzf678 Nov 30, 2022
e03d6fc
Merge branch 'master' into explain
fzzf678 Nov 30, 2022
a266cee
Merge branch 'master' into explain
fzzf678 Nov 30, 2022
6f6a94e
Merge remote-tracking branch 'upstream/master' into explain
fzzf678 Dec 1, 2022
083af04
Update parser.go
fzzf678 Dec 1, 2022
6fb7467
fix ut
fzzf678 Dec 1, 2022
00092e9
Merge branch 'master' into explain
ti-chi-bot Dec 1, 2022
1b2d7cc
Merge branch 'master' into explain
ti-chi-bot Dec 1, 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
94 changes: 94 additions & 0 deletions executor/explain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package executor_test

import (
"bytes"
"encoding/json"
"fmt"
"regexp"
"strconv"
Expand Down Expand Up @@ -515,3 +516,96 @@ func TestIssue35105(t *testing.T) {
require.Error(t, tk.ExecToErr("explain analyze insert into t values (1), (2), (3)"))
tk.MustQuery("select * from t").Check(testkit.Rows("2"))
}

func flatJSONPlan(j *plannercore.ExplainInfoForEncode) (res []*plannercore.ExplainInfoForEncode) {
if j == nil {
return
}
res = append(res, j)
for _, child := range j.SubOperators {
res = append(res, flatJSONPlan(child)...)
}
return
}

func TestExplainJSON(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec("drop table if exists t1, t2")
tk.MustExec("create table t1(id int, key(id))")
tk.MustExec("create table t2(id int, key(id))")
cases := []string{
"select * from t1",
"select count(*) from t2",
"select * from t1, t2 where t1.id = t2.id",
"select /*+ merge_join(t1, t2)*/ * from t1, t2 where t1.id = t2.id",
"with top10 as ( select * from t1 order by id desc limit 10 ) select * from top10 where id in (1,2)",
"insert into t1 values(1)",
"delete from t2 where t2.id > 10",
"update t2 set id = 1 where id =2",
"select * from t1 where t1.id < (select sum(t2.id) from t2 where t2.id = t1.id)",
}
// test syntax
tk.MustExec("explain format = 'tidb_json' select * from t1")
tk.MustExec("explain format = tidb_json select * from t1")
tk.MustExec("explain format = 'TIDB_JSON' select * from t1")
tk.MustExec("explain format = TIDB_JSON select * from t1")
tk.MustExec("explain analyze format = 'tidb_json' select * from t1")
tk.MustExec("explain analyze format = tidb_json select * from t1")
tk.MustExec("explain analyze format = 'TIDB_JSON' select * from t1")
tk.MustExec("explain analyze format = TIDB_JSON select * from t1")

// explain
for _, sql := range cases {
jsonForamt := "explain format = tidb_json " + sql
rowForamt := "explain format = row " + sql
resJSON := tk.MustQuery(jsonForamt).Rows()
resRow := tk.MustQuery(rowForamt).Rows()

j := new([]*plannercore.ExplainInfoForEncode)
require.NoError(t, json.Unmarshal([]byte(resJSON[0][0].(string)), j))
var flatJSONRows []*plannercore.ExplainInfoForEncode
for _, row := range *j {
flatJSONRows = append(flatJSONRows, flatJSONPlan(row)...)
}
require.Equal(t, len(flatJSONRows), len(resRow))

for i, row := range resRow {
require.Contains(t, row[0], flatJSONRows[i].ID)
require.Equal(t, flatJSONRows[i].EstRows, row[1])
require.Equal(t, flatJSONRows[i].TaskType, row[2])
require.Equal(t, flatJSONRows[i].AccessObject, row[3])
require.Equal(t, flatJSONRows[i].OperatorInfo, row[4])
}
}

// explain analyze
for _, sql := range cases {
jsonForamt := "explain analyze format = tidb_json " + sql
rowForamt := "explain analyze format = row " + sql
resJSON := tk.MustQuery(jsonForamt).Rows()
resRow := tk.MustQuery(rowForamt).Rows()

j := new([]*plannercore.ExplainInfoForEncode)
require.NoError(t, json.Unmarshal([]byte(resJSON[0][0].(string)), j))
var flatJSONRows []*plannercore.ExplainInfoForEncode
for _, row := range *j {
flatJSONRows = append(flatJSONRows, flatJSONPlan(row)...)
}
require.Equal(t, len(flatJSONRows), len(resRow))

for i, row := range resRow {
require.Contains(t, row[0], flatJSONRows[i].ID)
require.Equal(t, flatJSONRows[i].EstRows, row[1])
require.Equal(t, flatJSONRows[i].ActRows, row[2])
require.Equal(t, flatJSONRows[i].TaskType, row[3])
require.Equal(t, flatJSONRows[i].AccessObject, row[4])
require.Equal(t, flatJSONRows[i].OperatorInfo, row[6])
// executeInfo, memory, disk maybe vary in multi execution
require.NotEqual(t, flatJSONRows[i].ExecuteInfo, "")
require.NotEqual(t, flatJSONRows[i].MemoryInfo, "")
require.NotEqual(t, flatJSONRows[i].DiskInfo, "")
}
}
}
72 changes: 72 additions & 0 deletions executor/explainfor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package executor_test

import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"testing"
Expand Down Expand Up @@ -1395,3 +1396,74 @@ func TestIssue28792(t *testing.T) {
r2 := tk.MustQuery("EXPLAIN SELECT t12.a, t12.b FROM t12 LEFT JOIN t97 use index () on t12.b = t97.b;").Rows()
require.Equal(t, r2, r1)
}

func TestExplainForJSON(t *testing.T) {
store := testkit.CreateMockStore(t)
tk1 := testkit.NewTestKit(t, store)
tk2 := testkit.NewTestKit(t, store)

tk1.MustExec("use test")
tk1.MustExec("set @@tidb_enable_collect_execution_info=0;")
tk1.MustExec("drop table if exists t1")
tk1.MustExec("create table t1(id int);")
tk1.MustQuery("select * from t1;")
tk1RootProcess := tk1.Session().ShowProcess()
ps := []*util.ProcessInfo{tk1RootProcess}
tk1.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
tk2.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
resRow := tk2.MustQuery(fmt.Sprintf("explain format = 'row' for connection %d", tk1RootProcess.ID)).Rows()
resJSON := tk2.MustQuery(fmt.Sprintf("explain format = 'tidb_json' for connection %d", tk1RootProcess.ID)).Rows()

j := new([]*core.ExplainInfoForEncode)
require.NoError(t, json.Unmarshal([]byte(resJSON[0][0].(string)), j))
flatJSONRows := make([]*core.ExplainInfoForEncode, 0)
for _, row := range *j {
flatJSONRows = append(flatJSONRows, flatJSONPlan(row)...)
}
require.Equal(t, len(flatJSONRows), len(resRow))

for i, row := range resRow {
require.Contains(t, row[0], flatJSONRows[i].ID)
require.Equal(t, flatJSONRows[i].EstRows, row[1])
require.Equal(t, flatJSONRows[i].TaskType, row[2])
require.Equal(t, flatJSONRows[i].AccessObject, row[3])
require.Equal(t, flatJSONRows[i].OperatorInfo, row[4])
}

tk1.MustExec("set @@tidb_enable_collect_execution_info=1;")
tk1.MustExec("drop table if exists t2")
tk1.MustExec("create table t2(id int);")
tk1.MustQuery("select * from t2;")
tk1RootProcess = tk1.Session().ShowProcess()
ps = []*util.ProcessInfo{tk1RootProcess}
tk1.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
tk2.Session().SetSessionManager(&testkit.MockSessionManager{PS: ps})
resRow = tk2.MustQuery(fmt.Sprintf("explain format = 'row' for connection %d", tk1RootProcess.ID)).Rows()
resJSON = tk2.MustQuery(fmt.Sprintf("explain format = 'tidb_json' for connection %d", tk1RootProcess.ID)).Rows()

j = new([]*core.ExplainInfoForEncode)
require.NoError(t, json.Unmarshal([]byte(resJSON[0][0].(string)), j))
flatJSONRows = []*core.ExplainInfoForEncode{}
for _, row := range *j {
flatJSONRows = append(flatJSONRows, flatJSONPlan(row)...)
}
require.Equal(t, len(flatJSONRows), len(resRow))

for i, row := range resRow {
require.Contains(t, row[0], flatJSONRows[i].ID)
require.Equal(t, flatJSONRows[i].EstRows, row[1])
require.Equal(t, flatJSONRows[i].ActRows, row[2])
require.Equal(t, flatJSONRows[i].TaskType, row[3])
require.Equal(t, flatJSONRows[i].AccessObject, row[4])
require.Equal(t, flatJSONRows[i].OperatorInfo, row[6])
// executeInfo, memory, disk maybe vary in multi execution
require.NotEqual(t, flatJSONRows[i].ExecuteInfo, "")
require.NotEqual(t, flatJSONRows[i].MemoryInfo, "")
require.NotEqual(t, flatJSONRows[i].DiskInfo, "")
}
// test syntax
tk2.MustExec(fmt.Sprintf("explain format = 'tidb_json' for connection %d", tk1RootProcess.ID))
tk2.MustExec(fmt.Sprintf("explain format = tidb_json for connection %d", tk1RootProcess.ID))
tk2.MustExec(fmt.Sprintf("explain format = 'TIDB_JSON' for connection %d", tk1RootProcess.ID))
tk2.MustExec(fmt.Sprintf("explain format = TIDB_JSON for connection %d", tk1RootProcess.ID))
}
1 change: 1 addition & 0 deletions parser/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ var tokenMap = map[string]int{
"THEN": then,
"TIDB": tidb,
"TIDB_CURRENT_TSO": tidbCurrentTSO,
"TIDB_JSON": tidbJson,
"TIFLASH": tiFlash,
"TIKV_IMPORTER": tikvImporter,
"TIME": timeType,
Expand Down
Loading