From 03f385de5ff07e445b25c8703d088b7d6ee024e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AC=A7=E5=86=B0?= <32380374+ou-bing@users.noreply.github.com> Date: Tue, 8 Dec 2020 16:32:32 +0800 Subject: [PATCH] planner/core: use constant propagate before predicates push down (#21061) --- cmd/explaintest/r/explain_easy.result | 29 ++++++------ expression/testdata/expression_suite_out.json | 16 +++---- expression/testdata/partition_pruner_out.json | 28 ++++++------ planner/core/integration_test.go | 44 ++++++++++++++----- planner/core/rule_predicate_push_down.go | 1 + .../core/testdata/integration_suite_out.json | 2 +- .../testdata/plan_suite_unexported_out.json | 2 +- planner/core/testdata/point_get_plan_out.json | 2 +- util/ranger/testdata/ranger_suite_out.json | 6 +-- 9 files changed, 75 insertions(+), 55 deletions(-) diff --git a/cmd/explaintest/r/explain_easy.result b/cmd/explaintest/r/explain_easy.result index c0a846b044..c2f177b20f 100644 --- a/cmd/explaintest/r/explain_easy.result +++ b/cmd/explaintest/r/explain_easy.result @@ -425,10 +425,10 @@ IndexReader_6 10.00 root index:IndexRangeScan_5 └─IndexRangeScan_5 10.00 cop[tikv] table:t, index:idx(a, b) range:[1,1], keep order:false, stats:pseudo explain select * from t where a = 1 and a = 2; id estRows task access object operator info -TableDual_5 0.00 root rows:0 +TableDual_5 8000.00 root rows:0 explain select * from t where b = 1 and b = 2; id estRows task access object operator info -TableDual_5 0.00 root rows:0 +TableDual_5 8000.00 root rows:0 explain select * from t t1 join t t2 where t1.b = t2.b and t2.b is null; id estRows task access object operator info Projection_7 0.00 root test.t.a, test.t.b, test.t.a, test.t.b @@ -450,7 +450,7 @@ drop table if exists t; create table t(a bigint primary key); explain select * from t where a = 1 and a = 2; id estRows task access object operator info -TableDual_5 0.00 root rows:0 +TableDual_5 8000.00 root rows:0 explain select null or a > 1 from t; id estRows task access object operator info Projection_3 10000.00 root or(, gt(test.t.a, 1))->Column#2 @@ -498,18 +498,17 @@ PRIMARY KEY (`id`) EXPLAIN SELECT COUNT(1) FROM (SELECT COALESCE(b.region_name, '不详') region_name, SUM(a.registration_num) registration_num FROM (SELECT stat_date, show_date, region_id, 0 registration_num FROM test01 WHERE period = 1 AND stat_date >= 20191202 AND stat_date <= 20191202 UNION ALL SELECT stat_date, show_date, region_id, registration_num registration_num FROM test01 WHERE period = 1 AND stat_date >= 20191202 AND stat_date <= 20191202) a LEFT JOIN test02 b ON a.region_id = b.id WHERE registration_num > 0 AND a.stat_date >= '20191202' AND a.stat_date <= '20191202' GROUP BY a.stat_date , a.show_date , COALESCE(b.region_name, '不详') ) JLS; id estRows task access object operator info StreamAgg_22 1.00 root funcs:count(1)->Column#22 -└─HashAgg_25 1.00 root group by:Column#32, Column#33, Column#34, funcs:firstrow(1)->Column#31 - └─Projection_46 0.01 root Column#14, Column#15, coalesce(test.test02.region_name, 不详)->Column#34 - └─IndexMergeJoin_34 0.01 root left outer join, inner:TableReader_29, outer key:Column#16, inner key:test.test02.id - ├─Union_37(Build) 0.01 root - │ ├─Projection_38 0.00 root test.test01.stat_date, test.test01.show_date, test.test01.region_id - │ │ └─TableDual_39 0.00 root rows:0 - │ └─Projection_40 0.01 root test.test01.stat_date, test.test01.show_date, test.test01.region_id - │ └─TableReader_43 0.01 root data:Selection_42 - │ └─Selection_42 0.01 cop[tikv] eq(test.test01.period, 1), ge(test.test01.stat_date, 20191202), ge(test.test01.stat_date, 20191202), gt(cast(test.test01.registration_num), 0), le(test.test01.stat_date, 20191202), le(test.test01.stat_date, 20191202) - │ └─TableFullScan_41 10000.00 cop[tikv] table:test01 keep order:false, stats:pseudo - └─TableReader_29(Probe) 1.00 root data:TableRangeScan_28 - └─TableRangeScan_28 1.00 cop[tikv] table:b range: decided by [Column#16], keep order:true, stats:pseudo +└─HashAgg_48 8000.00 root group by:Column#32, Column#33, Column#34, funcs:firstrow(1)->Column#31 + └─Projection_49 10000.01 root Column#14, Column#15, coalesce(test.test02.region_name, 不详)->Column#34 + └─HashJoin_35 10000.01 root left outer join, equal:[eq(Column#16, test.test02.id)] + ├─TableReader_45(Build) 10000.00 root data:TableFullScan_44 + │ └─TableFullScan_44 10000.00 cop[tikv] table:b keep order:false, stats:pseudo + └─Union_37(Probe) 8000.01 root + ├─TableDual_39 8000.00 root rows:0 + └─Projection_40 0.01 root test.test01.stat_date, test.test01.show_date, test.test01.region_id + └─TableReader_43 0.01 root data:Selection_42 + └─Selection_42 0.01 cop[tikv] eq(test.test01.period, 1), ge(test.test01.stat_date, 20191202), ge(test.test01.stat_date, 20191202), gt(cast(test.test01.registration_num), 0), le(test.test01.stat_date, 20191202), le(test.test01.stat_date, 20191202) + └─TableFullScan_41 10000.00 cop[tikv] table:test01 keep order:false, stats:pseudo drop table if exists t; create table t(a int, nb int not null, nc int not null); explain select ifnull(a, 0) from t; diff --git a/expression/testdata/expression_suite_out.json b/expression/testdata/expression_suite_out.json index ddbd8c6678..a01315e45b 100644 --- a/expression/testdata/expression_suite_out.json +++ b/expression/testdata/expression_suite_out.json @@ -110,7 +110,7 @@ "Result": [ "HashJoin_6 100000.00 root CARTESIAN left outer join, other cond:gt(test.t1.a, test.t2.a)", "├─TableReader_12(Build) 10.00 root data:Selection_11", - "│ └─Selection_11 10.00 cop[tikv] eq(test.t2.a, 1), not(isnull(test.t2.a))", + "│ └─Selection_11 10.00 cop[tikv] eq(test.t2.a, 1)", "│ └─TableFullScan_10 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", "└─TableReader_9(Probe) 10000.00 root data:TableFullScan_8", " └─TableFullScan_8 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" @@ -121,7 +121,7 @@ "Result": [ "HashJoin_6 100000.00 root CARTESIAN right outer join, other cond:gt(test.t1.a, test.t2.a)", "├─TableReader_10(Build) 10.00 root data:Selection_9", - "│ └─Selection_9 10.00 cop[tikv] eq(test.t1.a, 1), not(isnull(test.t1.a))", + "│ └─Selection_9 10.00 cop[tikv] eq(test.t1.a, 1)", "│ └─TableFullScan_8 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo", "└─TableReader_12(Probe) 10000.00 root data:TableFullScan_11", " └─TableFullScan_11 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" @@ -151,9 +151,9 @@ { "SQL": "explain select * from t1 left join t2 on t2.a = t2.b and t2.a > 1", "Result": [ - "HashJoin_6 26666666.67 root CARTESIAN left outer join", - "├─TableReader_12(Build) 2666.67 root data:Selection_11", - "│ └─Selection_11 2666.67 cop[tikv] eq(test.t2.a, test.t2.b), gt(test.t2.a, 1)", + "HashJoin_6 8888888.89 root CARTESIAN left outer join", + "├─TableReader_12(Build) 888.89 root data:Selection_11", + "│ └─Selection_11 888.89 cop[tikv] eq(test.t2.a, test.t2.b), gt(test.t2.a, 1), gt(test.t2.b, 1)", "│ └─TableFullScan_10 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", "└─TableReader_9(Probe) 10000.00 root data:TableFullScan_8", " └─TableFullScan_8 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" @@ -234,10 +234,8 @@ { "SQL": "explain select * from t1 left join t2 on t2.a = 1 and t2.a = 2", "Result": [ - "HashJoin_6 10000.00 root CARTESIAN left outer join", - "├─TableReader_12(Build) 0.00 root data:Selection_11", - "│ └─Selection_11 0.00 cop[tikv] eq(test.t2.a, 1), eq(test.t2.a, 2)", - "│ └─TableFullScan_10 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo", + "HashJoin_6 80000000.00 root CARTESIAN left outer join", + "├─TableDual_10(Build) 8000.00 root rows:0", "└─TableReader_9(Probe) 10000.00 root data:TableFullScan_8", " └─TableFullScan_8 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" ] diff --git a/expression/testdata/partition_pruner_out.json b/expression/testdata/partition_pruner_out.json index c7d56352a6..589537a2e5 100644 --- a/expression/testdata/partition_pruner_out.json +++ b/expression/testdata/partition_pruner_out.json @@ -296,7 +296,7 @@ ], "Plan": [ "TableReader_7 0.01 root partition:p0,p1 data:Selection_6", - "└─Selection_6 0.01 cop[tikv] or(and(and(eq(test_partition.t2.id, 1), eq(test_partition.t2.a, 1)), eq(test_partition.t2.b, 1)), and(isnull(test_partition.t2.a), isnull(test_partition.t2.b)))", + "└─Selection_6 0.01 cop[tikv] or(and(eq(test_partition.t2.id, 1), and(eq(test_partition.t2.a, 1), eq(test_partition.t2.b, 1))), and(isnull(test_partition.t2.a), isnull(test_partition.t2.b)))", " └─TableFullScan_5 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" ] }, @@ -330,7 +330,7 @@ ], "Plan": [ "TableReader_7 0.00 root partition:p0 data:Selection_6", - "└─Selection_6 0.00 cop[tikv] or(and(and(eq(test_partition.t2.id, 1), eq(test_partition.t2.a, 1)), eq(test_partition.t2.b, 1)), and(and(eq(test_partition.t2.a, 1), eq(test_partition.t2.id, 1)), eq(test_partition.t2.b, 1)))", + "└─Selection_6 0.00 cop[tikv] or(and(eq(test_partition.t2.id, 1), and(eq(test_partition.t2.a, 1), eq(test_partition.t2.b, 1))), and(eq(test_partition.t2.a, 1), and(eq(test_partition.t2.id, 1), eq(test_partition.t2.b, 1))))", " └─TableFullScan_5 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" ] }, @@ -382,8 +382,8 @@ "SQL": "select * from t1 where a=id and id >10", "Result": null, "Plan": [ - "TableReader_7 2666.67 root partition:all data:Selection_6", - "└─Selection_6 2666.67 cop[tikv] eq(test_partition.t1.a, test_partition.t1.id), gt(test_partition.t1.id, 10)", + "TableReader_7 888.89 root partition:all data:Selection_6", + "└─Selection_6 888.89 cop[tikv] eq(test_partition.t1.a, test_partition.t1.id), gt(test_partition.t1.a, 10), gt(test_partition.t1.id, 10)", " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" ] }, @@ -391,8 +391,8 @@ "SQL": "select * from t2 where a=id and id >10", "Result": null, "Plan": [ - "TableReader_7 2666.67 root partition:all data:Selection_6", - "└─Selection_6 2666.67 cop[tikv] eq(test_partition.t2.a, test_partition.t2.id), gt(test_partition.t2.id, 10)", + "TableReader_7 888.89 root partition:all data:Selection_6", + "└─Selection_6 888.89 cop[tikv] eq(test_partition.t2.a, test_partition.t2.id), gt(test_partition.t2.a, 10), gt(test_partition.t2.id, 10)", " └─TableFullScan_5 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" ] }, @@ -400,8 +400,8 @@ "SQL": "select * from t3 where a=id and id >10", "Result": null, "Plan": [ - "TableReader_7 2666.67 root partition:all data:Selection_6", - "└─Selection_6 2666.67 cop[tikv] eq(test_partition.t3.a, test_partition.t3.id), gt(test_partition.t3.id, 10)", + "TableReader_7 888.89 root partition:all data:Selection_6", + "└─Selection_6 888.89 cop[tikv] eq(test_partition.t3.a, test_partition.t3.id), gt(test_partition.t3.a, 10), gt(test_partition.t3.id, 10)", " └─TableFullScan_5 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo" ] }, @@ -411,8 +411,8 @@ " " ], "Plan": [ - "TableReader_7 2674.00 root partition:all data:Selection_6", - "└─Selection_6 2674.00 cop[tikv] or(and(eq(test_partition.t1.a, test_partition.t1.id), gt(test_partition.t1.id, 10)), isnull(test_partition.t1.a))", + "TableReader_7 898.00 root partition:all data:Selection_6", + "└─Selection_6 898.00 cop[tikv] or(and(eq(test_partition.t1.a, test_partition.t1.id), and(gt(test_partition.t1.id, 10), gt(test_partition.t1.a, 10))), isnull(test_partition.t1.a))", " └─TableFullScan_5 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" ] }, @@ -422,8 +422,8 @@ " " ], "Plan": [ - "TableReader_7 2674.00 root partition:all data:Selection_6", - "└─Selection_6 2674.00 cop[tikv] or(and(eq(test_partition.t2.a, test_partition.t2.id), gt(test_partition.t2.id, 10)), isnull(test_partition.t2.a))", + "TableReader_7 898.00 root partition:all data:Selection_6", + "└─Selection_6 898.00 cop[tikv] or(and(eq(test_partition.t2.a, test_partition.t2.id), and(gt(test_partition.t2.id, 10), gt(test_partition.t2.a, 10))), isnull(test_partition.t2.a))", " └─TableFullScan_5 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo" ] }, @@ -433,8 +433,8 @@ " " ], "Plan": [ - "TableReader_7 2674.00 root partition:all data:Selection_6", - "└─Selection_6 2674.00 cop[tikv] or(and(eq(test_partition.t3.a, test_partition.t3.id), gt(test_partition.t3.id, 10)), isnull(test_partition.t3.a))", + "TableReader_7 898.00 root partition:all data:Selection_6", + "└─Selection_6 898.00 cop[tikv] or(and(eq(test_partition.t3.a, test_partition.t3.id), and(gt(test_partition.t3.id, 10), gt(test_partition.t3.a, 10))), isnull(test_partition.t3.a))", " └─TableFullScan_5 10000.00 cop[tikv] table:t3 keep order:false, stats:pseudo" ] }, diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 20bd1e91cf..b3276b0198 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1266,19 +1266,17 @@ func (s *testIntegrationSerialSuite) TestIndexMerge(c *C) { tk.MustExec("drop table if exists t") tk.MustExec("create table t (a int, b int, unique key(a), unique key(b))") tk.MustQuery("desc select /*+ use_index_merge(t) */ * from t where a =1 or (b=1 and b+2>1)").Check(testkit.Rows( - "Projection_4 1.80 root test.t.a, test.t.b", - "└─IndexMerge_9 2.00 root ", - " ├─IndexRangeScan_5(Build) 1.00 cop[tikv] table:t, index:a(a) range:[1,1], keep order:false, stats:pseudo", - " ├─Selection_7(Build) 0.80 cop[tikv] gt(plus(test.t.b, 2), 1)", - " │ └─IndexRangeScan_6 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false, stats:pseudo", - " └─TableRowIDScan_8(Probe) 2.00 cop[tikv] table:t keep order:false, stats:pseudo")) - tk.MustQuery("show warnings").Check(testkit.Rows()) + "TableReader_7 8000.00 root data:Selection_6", + "└─Selection_6 8000.00 cop[tikv] or(eq(test.t.a, 1), and(eq(test.t.b, 1), 1))", + " └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 IndexMerge is inapplicable or disabled")) tk.MustQuery("desc select /*+ use_index_merge(t) */ * from t where a =1 or (b=1 and length(b)=1)").Check(testkit.Rows( "Projection_4 1.80 root test.t.a, test.t.b", "└─IndexMerge_9 2.00 root ", " ├─IndexRangeScan_5(Build) 1.00 cop[tikv] table:t, index:a(a) range:[1,1], keep order:false, stats:pseudo", - " ├─Selection_7(Build) 0.80 cop[tikv] eq(length(cast(test.t.b)), 1)", + " ├─Selection_7(Build) 0.80 cop[tikv] eq(length(cast(1)), 1)", " │ └─IndexRangeScan_6 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false, stats:pseudo", " └─TableRowIDScan_8(Probe) 2.00 cop[tikv] table:t keep order:false, stats:pseudo")) tk.MustQuery("show warnings").Check(testkit.Rows()) @@ -1286,9 +1284,9 @@ func (s *testIntegrationSerialSuite) TestIndexMerge(c *C) { tk.MustQuery("desc select /*+ use_index_merge(t) */ * from t where (a=1 and length(a)=1) or (b=1 and length(b)=1)").Check(testkit.Rows( "Projection_4 1.60 root test.t.a, test.t.b", "└─IndexMerge_10 2.00 root ", - " ├─Selection_6(Build) 0.80 cop[tikv] eq(length(cast(test.t.a)), 1)", + " ├─Selection_6(Build) 0.80 cop[tikv] eq(length(cast(1)), 1)", " │ └─IndexRangeScan_5 1.00 cop[tikv] table:t, index:a(a) range:[1,1], keep order:false, stats:pseudo", - " ├─Selection_8(Build) 0.80 cop[tikv] eq(length(cast(test.t.b)), 1)", + " ├─Selection_8(Build) 0.80 cop[tikv] eq(length(cast(1)), 1)", " │ └─IndexRangeScan_7 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false, stats:pseudo", " └─TableRowIDScan_9(Probe) 2.00 cop[tikv] table:t keep order:false, stats:pseudo")) tk.MustQuery("show warnings").Check(testkit.Rows()) @@ -1834,7 +1832,33 @@ func (s *testIntegrationSuite) TestPartitionUnionWithPPruningColumn(c *C) { "2890 LE1300_r5", "3150 LE1323_r5", "3290 LE1327_r5")) +} +func (s *testIntegrationSuite) TestIssue20139(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t (id int, c int) partition by range (id) (partition p0 values less than (4), partition p1 values less than (7))") + tk.MustExec("insert into t values(3, 3), (5, 5)") + plan := tk.MustQuery("explain select * from t where c = 1 and id = c") + plan.Check(testkit.Rows( + "TableReader_7 0.01 root partition:p0 data:Selection_6", + "└─Selection_6 0.01 cop[tikv] eq(test.t.c, 1), eq(test.t.id, 1)", + " └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustExec("drop table t") +} + +func (s *testIntegrationSuite) TestIssue14481(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int default null, b int default null, c int default null)") + plan := tk.MustQuery("explain select * from t where a = 1 and a = 2") + plan.Check(testkit.Rows("TableDual_5 8000.00 root rows:0")) + tk.MustExec("drop table t") } func (s *testIntegrationSerialSuite) TestIssue20710(c *C) { diff --git a/planner/core/rule_predicate_push_down.go b/planner/core/rule_predicate_push_down.go index e3d0195c1b..d7d3939110 100644 --- a/planner/core/rule_predicate_push_down.go +++ b/planner/core/rule_predicate_push_down.go @@ -99,6 +99,7 @@ func (p *LogicalUnionScan) PredicatePushDown(predicates []expression.Expression) // PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (ds *DataSource) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) { + predicates = expression.PropagateConstant(ds.ctx, predicates) ds.allConds = predicates ds.pushedDownConds, predicates = expression.PushDownExprs(ds.ctx.GetSessionVars().StmtCtx, predicates, ds.ctx.GetClient(), kv.UnSpecified) return predicates, ds diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index 0ad109e42d..b516069fa2 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -285,7 +285,7 @@ "SQL": "explain select /*+ USE_INDEX_MERGE(t, a, b, c) */ * from t where 1 or t.a = 1 or t.b = 2", "Plan": [ "TableReader_7 8000.40 root data:Selection_6", - "└─Selection_6 8000.40 cop[tikv] or(or(1, eq(test.t.a, 1)), eq(test.t.b, 2))", + "└─Selection_6 8000.40 cop[tikv] or(1, or(eq(test.t.a, 1), eq(test.t.b, 2)))", " └─TableFullScan_5 10000.00 cop[tikv] table:t keep order:false, stats:pseudo" ] } diff --git a/planner/core/testdata/plan_suite_unexported_out.json b/planner/core/testdata/plan_suite_unexported_out.json index d0e73580b0..768ec61467 100644 --- a/planner/core/testdata/plan_suite_unexported_out.json +++ b/planner/core/testdata/plan_suite_unexported_out.json @@ -935,7 +935,7 @@ }, { "Left": "[]", - "Right": "[or(or(eq(test.t.a, 3), eq(test.t.a, 4)), eq(test.t.a, 2))]" + "Right": "[or(eq(test.t.a, 3), or(eq(test.t.a, 4), eq(test.t.a, 2)))]" }, { "Left": "[gt(test.t.a, 1)]", diff --git a/planner/core/testdata/point_get_plan_out.json b/planner/core/testdata/point_get_plan_out.json index 69a619da76..bb35328b74 100644 --- a/planner/core/testdata/point_get_plan_out.json +++ b/planner/core/testdata/point_get_plan_out.json @@ -15,7 +15,7 @@ { "SQL": "select b, c from t where t.b = 2 and t.c = 2 and t.b+1=3", "Plan": [ - "Selection_6 0.80 root eq(plus(test.t.b, 1), 3)", + "Selection_6 0.80 root 1", "└─Point_Get_5 1.00 root table:t, index:b(b, c) " ], "Res": [ diff --git a/util/ranger/testdata/ranger_suite_out.json b/util/ranger/testdata/ranger_suite_out.json index 1e3dde775b..1cdfbbc9e2 100644 --- a/util/ranger/testdata/ranger_suite_out.json +++ b/util/ranger/testdata/ranger_suite_out.json @@ -123,7 +123,7 @@ { "SQL": "select * from t where a = 1 and (b = 1 or b = 2) and b = 3 and c > 1;", "Plan": [ - "TableDual_5 0.00 root rows:0" + "TableDual_5 8000.00 root rows:0" ], "Result": null }, @@ -169,9 +169,7 @@ { "SQL": "select * from t where a = 1 and b is null and b = 1 and c > 1;", "Plan": [ - "IndexReader_7 0.27 root index:Selection_6", - "└─Selection_6 0.27 cop[tikv] isnull(test.t.b)", - " └─IndexRangeScan_5 0.33 cop[tikv] table:t, index:a(a, b, c) range:(1 1 1,1 1 +inf], keep order:false, stats:pseudo" + "TableDual_5 8000.00 root rows:0" ], "Result": null }