From b7ca406499ba1bb034aa51aaf22a3f3b5e6af9c5 Mon Sep 17 00:00:00 2001 From: wjHuang Date: Thu, 29 Sep 2022 16:07:45 +0800 Subject: [PATCH] planner: reopen CTE in apply only when correlate (#38214) close pingcap/tidb#38170 --- cmd/explaintest/r/cte.result | 20 ++++++++++++++++++++ cmd/explaintest/t/cte.test | 19 +++++++++++++++++++ planner/core/logical_plan_builder.go | 18 ++++++++++-------- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/cmd/explaintest/r/cte.result b/cmd/explaintest/r/cte.result index 3c8737d7400b8..55600df56f61d 100644 --- a/cmd/explaintest/r/cte.result +++ b/cmd/explaintest/r/cte.result @@ -805,3 +805,23 @@ a b 0 4 1 5 1 4 +CREATE TABLE `t_cqmg3b` ( +`wkey` int(11) DEFAULT NULL, +`pkey` int(11) NOT NULL, +`c_anpf_c` int(11) DEFAULT NULL, +`c_b_fp_c` text DEFAULT NULL, +`c_ndccfb` int(11) DEFAULT NULL, +`c_8rswc` int(11) DEFAULT NULL, +PRIMARY KEY (`pkey`) /*T![clustered_index] CLUSTERED */ +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +INSERT INTO `t_cqmg3b` VALUES (102,556000,NULL,'vbwxgc',NULL,NULL),(102,557000,NULL,'bfblud',NULL,NULL),(102,558000,NULL,'c6drnb',NULL,NULL),(102,559000,NULL,'fo_ezc',NULL,NULL),(102,560000,NULL,'btdes',NULL,NULL),(102,561000,NULL,'gy6zc',NULL,NULL),(102,562000,NULL,'9cyx9c',NULL,NULL),(102,563000,NULL,NULL,NULL,NULL),(103,564000,NULL,NULL,NULL,NULL),(103,565000,NULL,NULL,NULL,NULL),(103,566000,NULL,NULL,NULL,NULL),(103,567000,NULL,NULL,NULL,NULL),(103,568000,NULL,NULL,NULL,NULL),(103,569000,NULL,NULL,NULL,NULL),(103,570000,NULL,NULL,NULL,NULL),(105,578000,NULL,'fmicvd',NULL,NULL),(105,579000,NULL,'_tflkc',NULL,NULL),(105,580000,NULL,'xhovz',NULL,NULL),(105,581000,NULL,'n5bak',NULL,NULL),(105,582000,NULL,'gszus',NULL,NULL),(105,583000,NULL,'ewvydd',NULL,NULL),(105,584000,NULL,'fbzr0d',NULL,NULL),(107,590000,NULL,'8kgdf',NULL,NULL),(107,591000,NULL,'28v4bc',NULL,NULL),(107,592000,NULL,'evujpb',NULL,NULL),(107,593000,NULL,'8nkbzd',NULL,NULL),(107,594000,NULL,NULL,NULL,NULL),(109,599000,NULL,'1zswm',NULL,NULL),(109,600000,NULL,'gxlzrc',NULL,NULL),(109,601000,NULL,'xmedjc',NULL,NULL),(110,602000,NULL,'jwym6',NULL,NULL),(110,603000,NULL,NULL,NULL,NULL),(110,604000,NULL,'pcckxd',NULL,NULL),(111,605000,NULL,'lhvvp',NULL,NULL),(111,606000,NULL,'5eyidd',NULL,NULL),(111,607000,NULL,'l8azic',NULL,NULL),(111,608000,NULL,'_lmxx',NULL,NULL),(112,609000,NULL,'cstovb',NULL,NULL),(112,610000,NULL,'9bcdjc',NULL,NULL),(112,611000,NULL,'7zofhc',NULL,NULL),(112,612000,NULL,'pe2a3',NULL,NULL),(112,613000,NULL,'xtoet',NULL,NULL),(112,614000,NULL,'unvnj',NULL,NULL),(112,615000,NULL,'fj4v1b',NULL,NULL); +CREATE TABLE `t_dnmxh` ( +`wkey` int(11) DEFAULT NULL, +`pkey` int(11) NOT NULL, +`c_xhsndb` double DEFAULT NULL, +PRIMARY KEY (`pkey`) /*T![clustered_index] CLUSTERED */ +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +INSERT INTO `t_dnmxh` VALUES (104,571000,NULL),(104,572000,44.37),(104,573000,59.91),(104,574000,91.5),(104,575000,9.53),(104,576000,92.4),(104,577000,47.96),(106,585000,NULL),(106,586000,NULL),(106,587000,NULL),(106,588000,NULL),(106,589000,NULL),(108,595000,13.35),(108,596000,13.51),(108,597000,47.51),(108,598000,NULL),(113,616000,24.73),(113,617000,NULL),(113,618000,92.6),(113,619000,NULL),(113,620000,91.65),(113,621000,100.46),(113,622000,31.3),(113,623000,63.81); +WITH cte_0 AS (select distinct ref_0.wkey as c0, ref_0.pkey as c1, ref_0.c_xhsndb as c2 from t_dnmxh as ref_0 where (1 <= ( select ref_1.pkey not in ( select ref_5.wkey as c0 from t_dnmxh as ref_5 where (ref_5.wkey < ( select ref_6.pkey as c0 from t_cqmg3b as ref_6 where 88 between 96 and 76)) ) as c0 from (t_cqmg3b as ref_1 left outer join t_dnmxh as ref_2 on (ref_1.wkey = ref_2.wkey )) where ref_0.c_xhsndb is NULL union select 33 <= 91 as c0 from t_cqmg3b as ref_8 ))), cte_1 AS (select ref_9.wkey as c0, ref_9.pkey as c1, ref_9.c_anpf_c as c2, ref_9.c_b_fp_c as c3, ref_9.c_ndccfb as c4, ref_9.c_8rswc as c5 from t_cqmg3b as ref_9) select count(1) from cte_0 as ref_10 where case when 56 < 50 then case when 100 in ( select distinct ref_11.c4 as c0 from cte_1 as ref_11 where (ref_11.c4 > ( select ref_13.pkey as c0 from t_dnmxh as ref_13 where (ref_13.wkey > ( select distinct ref_11.c1 as c0 from cte_0 as ref_14)) )) or (1 = 1)) then null else null end else '7mxv6' end not like 'ki4%vc'; +count(1) +24 diff --git a/cmd/explaintest/t/cte.test b/cmd/explaintest/t/cte.test index 0c1623caa81dd..13edac8f6002e 100644 --- a/cmd/explaintest/t/cte.test +++ b/cmd/explaintest/t/cte.test @@ -314,3 +314,22 @@ drop view if exists v1; create view v1 as with t1 as (with t11 as (select * from t1) select * from t1, t2) select * from t1; use test1; select * from test.v1; +# case +CREATE TABLE `t_cqmg3b` ( + `wkey` int(11) DEFAULT NULL, + `pkey` int(11) NOT NULL, + `c_anpf_c` int(11) DEFAULT NULL, + `c_b_fp_c` text DEFAULT NULL, + `c_ndccfb` int(11) DEFAULT NULL, + `c_8rswc` int(11) DEFAULT NULL, + PRIMARY KEY (`pkey`) /*T![clustered_index] CLUSTERED */ +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +INSERT INTO `t_cqmg3b` VALUES (102,556000,NULL,'vbwxgc',NULL,NULL),(102,557000,NULL,'bfblud',NULL,NULL),(102,558000,NULL,'c6drnb',NULL,NULL),(102,559000,NULL,'fo_ezc',NULL,NULL),(102,560000,NULL,'btdes',NULL,NULL),(102,561000,NULL,'gy6zc',NULL,NULL),(102,562000,NULL,'9cyx9c',NULL,NULL),(102,563000,NULL,NULL,NULL,NULL),(103,564000,NULL,NULL,NULL,NULL),(103,565000,NULL,NULL,NULL,NULL),(103,566000,NULL,NULL,NULL,NULL),(103,567000,NULL,NULL,NULL,NULL),(103,568000,NULL,NULL,NULL,NULL),(103,569000,NULL,NULL,NULL,NULL),(103,570000,NULL,NULL,NULL,NULL),(105,578000,NULL,'fmicvd',NULL,NULL),(105,579000,NULL,'_tflkc',NULL,NULL),(105,580000,NULL,'xhovz',NULL,NULL),(105,581000,NULL,'n5bak',NULL,NULL),(105,582000,NULL,'gszus',NULL,NULL),(105,583000,NULL,'ewvydd',NULL,NULL),(105,584000,NULL,'fbzr0d',NULL,NULL),(107,590000,NULL,'8kgdf',NULL,NULL),(107,591000,NULL,'28v4bc',NULL,NULL),(107,592000,NULL,'evujpb',NULL,NULL),(107,593000,NULL,'8nkbzd',NULL,NULL),(107,594000,NULL,NULL,NULL,NULL),(109,599000,NULL,'1zswm',NULL,NULL),(109,600000,NULL,'gxlzrc',NULL,NULL),(109,601000,NULL,'xmedjc',NULL,NULL),(110,602000,NULL,'jwym6',NULL,NULL),(110,603000,NULL,NULL,NULL,NULL),(110,604000,NULL,'pcckxd',NULL,NULL),(111,605000,NULL,'lhvvp',NULL,NULL),(111,606000,NULL,'5eyidd',NULL,NULL),(111,607000,NULL,'l8azic',NULL,NULL),(111,608000,NULL,'_lmxx',NULL,NULL),(112,609000,NULL,'cstovb',NULL,NULL),(112,610000,NULL,'9bcdjc',NULL,NULL),(112,611000,NULL,'7zofhc',NULL,NULL),(112,612000,NULL,'pe2a3',NULL,NULL),(112,613000,NULL,'xtoet',NULL,NULL),(112,614000,NULL,'unvnj',NULL,NULL),(112,615000,NULL,'fj4v1b',NULL,NULL); +CREATE TABLE `t_dnmxh` ( + `wkey` int(11) DEFAULT NULL, + `pkey` int(11) NOT NULL, + `c_xhsndb` double DEFAULT NULL, + PRIMARY KEY (`pkey`) /*T![clustered_index] CLUSTERED */ +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; +INSERT INTO `t_dnmxh` VALUES (104,571000,NULL),(104,572000,44.37),(104,573000,59.91),(104,574000,91.5),(104,575000,9.53),(104,576000,92.4),(104,577000,47.96),(106,585000,NULL),(106,586000,NULL),(106,587000,NULL),(106,588000,NULL),(106,589000,NULL),(108,595000,13.35),(108,596000,13.51),(108,597000,47.51),(108,598000,NULL),(113,616000,24.73),(113,617000,NULL),(113,618000,92.6),(113,619000,NULL),(113,620000,91.65),(113,621000,100.46),(113,622000,31.3),(113,623000,63.81); +WITH cte_0 AS (select distinct ref_0.wkey as c0, ref_0.pkey as c1, ref_0.c_xhsndb as c2 from t_dnmxh as ref_0 where (1 <= ( select ref_1.pkey not in ( select ref_5.wkey as c0 from t_dnmxh as ref_5 where (ref_5.wkey < ( select ref_6.pkey as c0 from t_cqmg3b as ref_6 where 88 between 96 and 76)) ) as c0 from (t_cqmg3b as ref_1 left outer join t_dnmxh as ref_2 on (ref_1.wkey = ref_2.wkey )) where ref_0.c_xhsndb is NULL union select 33 <= 91 as c0 from t_cqmg3b as ref_8 ))), cte_1 AS (select ref_9.wkey as c0, ref_9.pkey as c1, ref_9.c_anpf_c as c2, ref_9.c_b_fp_c as c3, ref_9.c_ndccfb as c4, ref_9.c_8rswc as c5 from t_cqmg3b as ref_9) select count(1) from cte_0 as ref_10 where case when 56 < 50 then case when 100 in ( select distinct ref_11.c4 as c0 from cte_1 as ref_11 where (ref_11.c4 > ( select ref_13.pkey as c0 from t_dnmxh as ref_13 where (ref_13.wkey > ( select distinct ref_11.c1 as c0 from cte_0 as ref_14)) )) or (1 = 1)) then null else null end else '7mxv6' end not like 'ki4%vc'; diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 3831969e471fb..abaa903ea6a5a 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -4881,12 +4881,12 @@ func (b *PlanBuilder) buildProjUponView(ctx context.Context, dbName model.CIStr, // every row from outerPlan and the whole innerPlan. func (b *PlanBuilder) buildApplyWithJoinType(outerPlan, innerPlan LogicalPlan, tp JoinType) LogicalPlan { b.optFlag = b.optFlag | flagPredicatePushDown | flagBuildKeyInfo | flagDecorrelate - setIsInApplyForCTE(innerPlan) ap := LogicalApply{LogicalJoin: LogicalJoin{JoinType: tp}}.Init(b.ctx, b.getSelectOffset()) ap.SetChildren(outerPlan, innerPlan) ap.names = make([]*types.FieldName, outerPlan.Schema().Len()+innerPlan.Schema().Len()) copy(ap.names, outerPlan.OutputNames()) ap.SetSchema(expression.MergeSchema(outerPlan.Schema(), innerPlan.Schema())) + setIsInApplyForCTE(innerPlan, ap.Schema()) // Note that, tp can only be LeftOuterJoin or InnerJoin, so we don't consider other outer joins. if tp == LeftOuterJoin { b.optFlag = b.optFlag | flagEliminateOuterJoin @@ -4907,27 +4907,29 @@ func (b *PlanBuilder) buildSemiApply(outerPlan, innerPlan LogicalPlan, condition return nil, err } - setIsInApplyForCTE(innerPlan) + setIsInApplyForCTE(innerPlan, join.Schema()) ap := &LogicalApply{LogicalJoin: *join} ap.tp = plancodec.TypeApply ap.self = ap return ap, nil } -// setIsInApplyForCTE indicates CTE is the in inner side of Apply, +// setIsInApplyForCTE indicates CTE is the in inner side of Apply and correlate. // the storage of cte needs to be reset for each outer row. // It's better to handle this in CTEExec.Close(), but cte storage is closed when SQL is finished. -func setIsInApplyForCTE(p LogicalPlan) { +func setIsInApplyForCTE(p LogicalPlan, apSchema *expression.Schema) { switch x := p.(type) { case *LogicalCTE: - x.cte.IsInApply = true - setIsInApplyForCTE(x.cte.seedPartLogicalPlan) + if len(extractCorColumnsBySchema4LogicalPlan(p, apSchema)) > 0 { + x.cte.IsInApply = true + } + setIsInApplyForCTE(x.cte.seedPartLogicalPlan, apSchema) if x.cte.recursivePartLogicalPlan != nil { - setIsInApplyForCTE(x.cte.recursivePartLogicalPlan) + setIsInApplyForCTE(x.cte.recursivePartLogicalPlan, apSchema) } default: for _, child := range p.Children() { - setIsInApplyForCTE(child) + setIsInApplyForCTE(child, apSchema) } } }