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

*: add foreign key check/cascade information in explain result #39167

Merged
merged 28 commits into from
Nov 22, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
756ffcb
*: support explain with foreign key check/cascade
crazycs520 Nov 15, 2022
1a5a715
refine code
crazycs520 Nov 15, 2022
cee28ef
tiny fix
crazycs520 Nov 15, 2022
4c31703
add normalize plan with foreign key test
crazycs520 Nov 15, 2022
0a15163
tiny refine
crazycs520 Nov 15, 2022
a187b9e
fix ci
crazycs520 Nov 15, 2022
0776206
Merge branch 'master' into fk-explain
crazycs520 Nov 15, 2022
a64d6b5
fix ci
crazycs520 Nov 15, 2022
15bbefd
Merge branch 'fk-explain' of https://github.com/crazycs520/tidb into …
crazycs520 Nov 15, 2022
76f02b2
move test to address comment
crazycs520 Nov 17, 2022
06f6151
address comment
crazycs520 Nov 18, 2022
41cc9e7
address comment
crazycs520 Nov 18, 2022
6d68562
Merge branch 'master' of https://github.com/pingcap/tidb into fk-explain
crazycs520 Nov 18, 2022
8d453e9
make ci stable
crazycs520 Nov 18, 2022
e5f9543
Merge branch 'master' of https://github.com/pingcap/tidb into fk-explain
crazycs520 Nov 18, 2022
4c0bf4c
remove bin
crazycs520 Nov 18, 2022
bea9776
fix bug
crazycs520 Nov 18, 2022
0ba0320
add more test
crazycs520 Nov 18, 2022
c45b10c
add more test
crazycs520 Nov 18, 2022
ffbee96
Merge branch 'master' into fk-explain
crazycs520 Nov 18, 2022
ffea8f1
Merge branch 'master' into fk-explain
hawkingrei Nov 18, 2022
e541b93
Merge branch 'master' into fk-explain
crazycs520 Nov 21, 2022
267411b
Merge branch 'master' into fk-explain
crazycs520 Nov 21, 2022
7f816d4
Merge branch 'master' into fk-explain
crazycs520 Nov 22, 2022
0798894
refine test
crazycs520 Nov 22, 2022
2bfdef2
Merge branch 'master' into fk-explain
crazycs520 Nov 22, 2022
c4d4ed8
Merge branch 'master' into fk-explain
crazycs520 Nov 22, 2022
e909926
Merge branch 'master' into fk-explain
ti-chi-bot Nov 22, 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
119 changes: 119 additions & 0 deletions cmd/explaintest/r/explain_foreign_key.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
set @@global.tidb_enable_foreign_key=1;
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
set @@foreign_key_checks=1;
use test;
drop table if exists t1,t2;
create table t1 (id int key);
create table t2 (id int key, foreign key fk(id) references t1(id) ON UPDATE CASCADE ON DELETE CASCADE);
create table t3 (id int, unique index idx(id));
create table t4 (id int, index idx_id(id),foreign key fk(id) references t3(id));
create table t5 (id int key, id2 int, id3 int, unique index idx2(id2), index idx3(id3));
create table t6 (id int, id2 int, id3 int, index idx_id(id), index idx_id2(id2), foreign key fk_1 (id) references t5(id) ON UPDATE CASCADE ON DELETE CASCADE, foreign key fk_2 (id2) references t5(id2) ON UPDATE CASCADE, foreign key fk_3 (id3) references t5(id3) ON DELETE CASCADE);
explain insert into t2 values (1);
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_3 0.00 root table:t1 foreign_key:fk, check_exist
explain update t2 set id=id+1 where id = 1;
id estRows task access object operator info
Update_3 N/A root N/A
└─Point_Get_1 1.00 root table:t2 handle:1, lock
└─Foreign_Key_Check_4 0.00 root table:t1 foreign_key:fk, check_exist
explain delete from t1 where id > 1;
id estRows task access object operator info
Delete_5 N/A root N/A
└─SelectLock_7 3333.33 root for update 0
└─TableReader_9 3333.33 root data:TableRangeScan_8
└─TableRangeScan_8 3333.33 cop[tikv] table:t1 range:(1,+inf], keep order:false, stats:pseudo
└─Foreign_Key_Cascade_10 0.00 root table:t2 foreign_key:fk, on_delete:CASCADE
explain update t1 set id=id+1 where id = 1;
id estRows task access object operator info
Update_3 N/A root N/A
└─Point_Get_1 1.00 root table:t1 handle:1, lock
└─Foreign_Key_Cascade_4 0.00 root table:t2 foreign_key:fk, on_update:CASCADE
explain insert into t1 values (1);
id estRows task access object operator info
Insert_1 N/A root N/A
explain insert into t1 values (1) on duplicate key update id = 100;
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Cascade_3 0.00 root table:t2 foreign_key:fk, on_update:CASCADE
explain insert into t4 values (1);
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_3 0.00 root table:t3, index:idx foreign_key:fk, check_exist
explain update t4 set id=id+1 where id = 1;
id estRows task access object operator info
Update_5 N/A root N/A
└─SelectLock_7 10.00 root for update 0
└─IndexReader_9 10.00 root index:IndexRangeScan_8
└─IndexRangeScan_8 10.00 cop[tikv] table:t4, index:idx_id(id) range:[1,1], keep order:false, stats:pseudo
└─Foreign_Key_Check_10 0.00 root table:t3, index:idx foreign_key:fk, check_exist
explain delete from t3 where id > 1;
id estRows task access object operator info
Delete_5 N/A root N/A
└─SelectLock_7 3333.33 root for update 0
└─IndexReader_9 3333.33 root index:IndexRangeScan_8
└─IndexRangeScan_8 3333.33 cop[tikv] table:t3, index:idx(id) range:(1,+inf], keep order:false, stats:pseudo
└─Foreign_Key_Check_10 0.00 root table:t4, index:idx_id foreign_key:fk, check_not_exist
explain update t3 set id=id+1 where id = 1;
id estRows task access object operator info
Update_3 N/A root N/A
└─Point_Get_1 1.00 root table:t3, index:idx(id) lock
└─Foreign_Key_Check_4 0.00 root table:t4, index:idx_id foreign_key:fk, check_not_exist
explain insert into t3 values (1);
id estRows task access object operator info
Insert_1 N/A root N/A
explain insert into t3 values (1) on duplicate key update id = 100;
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_3 0.00 root table:t4, index:idx_id foreign_key:fk, check_not_exist
explain insert into t6 values (1,1,1);
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_3 0.00 root table:t5 foreign_key:fk_1, check_exist
└─Foreign_Key_Check_4 0.00 root table:t5, index:idx2 foreign_key:fk_2, check_exist
└─Foreign_Key_Check_5 0.00 root table:t5, index:idx3 foreign_key:fk_3, check_exist
explain update t6 set id=id+1, id3=id2+1 where id = 1;
id estRows task access object operator info
Update_5 N/A root N/A
└─SelectLock_7 10.00 root for update 0
└─IndexLookUp_13 10.00 root
├─IndexRangeScan_11(Build) 10.00 cop[tikv] table:t6, index:idx_id(id) range:[1,1], keep order:false, stats:pseudo
└─TableRowIDScan_12(Probe) 10.00 cop[tikv] table:t6 keep order:false, stats:pseudo
└─Foreign_Key_Check_14 0.00 root table:t5 foreign_key:fk_1, check_exist
└─Foreign_Key_Check_15 0.00 root table:t5, index:idx3 foreign_key:fk_3, check_exist
explain delete from t5 where id > 1;
id estRows task access object operator info
Delete_5 N/A root N/A
└─SelectLock_7 3333.33 root for update 0
└─TableReader_9 3333.33 root data:TableRangeScan_8
└─TableRangeScan_8 3333.33 cop[tikv] table:t5 range:(1,+inf], keep order:false, stats:pseudo
└─Foreign_Key_Check_11 0.00 root table:t6, index:idx_id2 foreign_key:fk_2, check_not_exist
└─Foreign_Key_Cascade_10 0.00 root table:t6, index:idx_id foreign_key:fk_1, on_delete:CASCADE
└─Foreign_Key_Cascade_12 0.00 root table:t6, index:fk_3 foreign_key:fk_3, on_delete:CASCADE
explain update t5 set id=id+1, id2=id2+1 where id = 1;
id estRows task access object operator info
Update_4 N/A root N/A
└─Point_Get_1 1.00 root table:t5 handle:1, lock
└─Foreign_Key_Cascade_5 0.00 root table:t6, index:idx_id foreign_key:fk_1, on_update:CASCADE
└─Foreign_Key_Cascade_6 0.00 root table:t6, index:idx_id2 foreign_key:fk_2, on_update:CASCADE
explain update t5 set id=id+1, id2=id2+1, id3=id3+1 where id = 1;
id estRows task access object operator info
Update_5 N/A root N/A
└─Point_Get_1 1.00 root table:t5 handle:1, lock
└─Foreign_Key_Check_8 0.00 root table:t6, index:fk_3 foreign_key:fk_3, check_not_exist
└─Foreign_Key_Cascade_6 0.00 root table:t6, index:idx_id foreign_key:fk_1, on_update:CASCADE
└─Foreign_Key_Cascade_7 0.00 root table:t6, index:idx_id2 foreign_key:fk_2, on_update:CASCADE
explain insert into t5 values (1,1,1);
id estRows task access object operator info
Insert_1 N/A root N/A
explain insert into t5 values (1,1,1) on duplicate key update id = 100, id3=100;
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_4 0.00 root table:t6, index:fk_3 foreign_key:fk_3, check_not_exist
└─Foreign_Key_Cascade_3 0.00 root table:t6, index:idx_id foreign_key:fk_1, on_update:CASCADE
explain insert into t5 values (1,1,1) on duplicate key update id = 100, id2=100, id3=100;
id estRows task access object operator info
Insert_1 N/A root N/A
└─Foreign_Key_Check_5 0.00 root table:t6, index:fk_3 foreign_key:fk_3, check_not_exist
└─Foreign_Key_Cascade_3 0.00 root table:t6, index:idx_id foreign_key:fk_1, on_update:CASCADE
└─Foreign_Key_Cascade_4 0.00 root table:t6, index:idx_id2 foreign_key:fk_2, on_update:CASCADE
31 changes: 31 additions & 0 deletions cmd/explaintest/t/explain_foreign_key.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
set @@global.tidb_enable_foreign_key=1;
set @@foreign_key_checks=1;
use test;
drop table if exists t1,t2;
create table t1 (id int key);
create table t2 (id int key, foreign key fk(id) references t1(id) ON UPDATE CASCADE ON DELETE CASCADE);
create table t3 (id int, unique index idx(id));
create table t4 (id int, index idx_id(id),foreign key fk(id) references t3(id));
create table t5 (id int key, id2 int, id3 int, unique index idx2(id2), index idx3(id3));
create table t6 (id int, id2 int, id3 int, index idx_id(id), index idx_id2(id2), foreign key fk_1 (id) references t5(id) ON UPDATE CASCADE ON DELETE CASCADE, foreign key fk_2 (id2) references t5(id2) ON UPDATE CASCADE, foreign key fk_3 (id3) references t5(id3) ON DELETE CASCADE);

explain insert into t2 values (1);
explain update t2 set id=id+1 where id = 1;
explain delete from t1 where id > 1;
explain update t1 set id=id+1 where id = 1;
explain insert into t1 values (1);
explain insert into t1 values (1) on duplicate key update id = 100;
explain insert into t4 values (1);
explain update t4 set id=id+1 where id = 1;
explain delete from t3 where id > 1;
explain update t3 set id=id+1 where id = 1;
explain insert into t3 values (1);
explain insert into t3 values (1) on duplicate key update id = 100;
explain insert into t6 values (1,1,1);
explain update t6 set id=id+1, id3=id2+1 where id = 1;
explain delete from t5 where id > 1;
explain update t5 set id=id+1, id2=id2+1 where id = 1;
explain update t5 set id=id+1, id2=id2+1, id3=id3+1 where id = 1;
explain insert into t5 values (1,1,1);
explain insert into t5 values (1,1,1) on duplicate key update id = 100, id3=100;
explain insert into t5 values (1,1,1) on duplicate key update id = 100, id2=100, id3=100;
9 changes: 9 additions & 0 deletions planner/core/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,14 @@ func NormalizeFlatPlan(flat *FlatPhysicalPlan) (normalized string, digest *parse
// assume an operator costs around 30 bytes, preallocate space for them
d.buf.Grow(30 * len(selectPlan))
depthOffset := len(flat.Main) - len(selectPlan)
loop1:
for _, op := range selectPlan {
taskTypeInfo := plancodec.EncodeTaskTypeForNormalize(op.IsRoot, op.StoreType)
switch op.Origin.(type) {
case *FKCheck, *FKCascade:
// Generate plan digest doesn't need to contain the foreign key check/cascade plan, so just break the loop.
break loop1
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
}
p := op.Origin.(PhysicalPlan)
plancodec.NormalizePlanNode(
int(op.Depth-uint32(depthOffset)),
Expand All @@ -287,6 +293,9 @@ func NormalizeFlatPlan(flat *FlatPhysicalPlan) (normalized string, digest *parse
)
}
normalized = d.buf.String()
if len(normalized) == 0 {
return "", parser.NewDigest(nil)
}
_, err := d.hasher.Write(d.buf.Bytes())
if err != nil {
panic(err)
Expand Down
32 changes: 32 additions & 0 deletions planner/core/flat_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ func (f *FlatPhysicalPlan) flattenRecursively(p Plan, info *operatorCtx, target
target, childIdx = f.flattenRecursively(plan.SelectPlan, childCtx, target)
childIdxs = append(childIdxs, childIdx)
}
target, childIdxs = f.flattenForeignKeyChecksAndCascades(childCtx, target, childIdxs, plan.FKChecks, plan.FKCascades)
case *Update:
if plan.SelectPlan != nil {
childCtx.isRoot = true
Expand All @@ -360,6 +361,12 @@ func (f *FlatPhysicalPlan) flattenRecursively(p Plan, info *operatorCtx, target
target, childIdx = f.flattenRecursively(plan.SelectPlan, childCtx, target)
childIdxs = append(childIdxs, childIdx)
}
for _, fkChecks := range plan.FKChecks {
target, childIdxs = f.flattenForeignKeyChecksAndCascades(childCtx, target, childIdxs, fkChecks, nil)
}
for _, fkCascades := range plan.FKCascades {
target, childIdxs = f.flattenForeignKeyChecksAndCascades(childCtx, target, childIdxs, nil, fkCascades)
}
case *Delete:
if plan.SelectPlan != nil {
childCtx.isRoot = true
Expand All @@ -368,6 +375,12 @@ func (f *FlatPhysicalPlan) flattenRecursively(p Plan, info *operatorCtx, target
target, childIdx = f.flattenRecursively(plan.SelectPlan, childCtx, target)
childIdxs = append(childIdxs, childIdx)
}
for _, fkChecks := range plan.FKChecks {
crazycs520 marked this conversation as resolved.
Show resolved Hide resolved
target, childIdxs = f.flattenForeignKeyChecksAndCascades(childCtx, target, childIdxs, fkChecks, nil)
}
for _, fkCascades := range plan.FKCascades {
target, childIdxs = f.flattenForeignKeyChecksAndCascades(childCtx, target, childIdxs, nil, fkCascades)
}
case *Execute:
f.InExecute = true
if plan.Plan != nil {
Expand Down Expand Up @@ -401,6 +414,25 @@ func (f *FlatPhysicalPlan) flattenRecursively(p Plan, info *operatorCtx, target
return target, idx
}

func (f *FlatPhysicalPlan) flattenForeignKeyChecksAndCascades(childCtx *operatorCtx, target FlatPlanTree, childIdxs []int, fkChecks []*FKCheck, fkCascades []*FKCascade) (FlatPlanTree, []int) {
var childIdx int
for _, fkCheck := range fkChecks {
childCtx.isRoot = true
childCtx.label = Empty
childCtx.isLastChild = true
target, childIdx = f.flattenRecursively(fkCheck, childCtx, target)
childIdxs = append(childIdxs, childIdx)
}
for _, fkCascade := range fkCascades {
childCtx.isRoot = true
childCtx.label = Empty
childCtx.isLastChild = true
target, childIdx = f.flattenRecursively(fkCascade, childCtx, target)
childIdxs = append(childIdxs, childIdx)
}
return target, childIdxs
}

func (f *FlatPhysicalPlan) flattenCTERecursively(cteDef *CTEDefinition, info *operatorCtx, target FlatPlanTree) FlatPlanTree {
flat := f.flattenSingle(cteDef, info)
if flat != nil {
Expand Down
Loading