From 31bee13e9b9fda9e988a16e6fd9e346b8ce2e8a5 Mon Sep 17 00:00:00 2001 From: Kenan Yao Date: Mon, 8 Mar 2021 15:50:56 +0800 Subject: [PATCH] cherry pick #23132 to release-5.0-rc Signed-off-by: ti-srebot --- planner/core/integration_test.go | 49 ++++++++++++++++--- planner/core/stats.go | 11 ++--- .../core/testdata/integration_suite_out.json | 11 +++-- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index c2f0a56ec313d..9d980d8ca0123 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1275,7 +1275,7 @@ func (s *testIntegrationSerialSuite) TestIssue16837(c *C) { "└─IndexMerge_9 0.01 root ", " ├─IndexRangeScan_5(Build) 10.00 cop[tikv] table:t, index:idx_ab(a, b) range:[1,1], keep order:false, stats:pseudo", " ├─IndexRangeScan_6(Build) 1.00 cop[tikv] table:t, index:c(c) range:[1,1], keep order:false, stats:pseudo", - " └─Selection_8(Probe) 0.01 cop[tikv] eq(test.t.e, 1)", + " └─Selection_8(Probe) 0.01 cop[tikv] or(eq(test.t.a, 1), and(eq(test.t.e, 1), eq(test.t.c, 1)))", " └─TableRowIDScan_7 11.00 cop[tikv] table:t keep order:false, stats:pseudo")) tk.MustQuery("show warnings").Check(testkit.Rows()) tk.MustExec("insert into t values (2, 1, 1, 1, 2)") @@ -1317,10 +1317,14 @@ func (s *testIntegrationSerialSuite) TestIndexMerge(c *C) { tk.MustQuery("show warnings").Check(testkit.Rows()) tk.MustQuery("desc select /*+ use_index_merge(t) */ * from t where (a=1 and length(b)=1) or (b=1 and length(a)=1)").Check(testkit.Rows( - "TableReader_7 1.60 root data:Selection_6", - "└─Selection_6 1.60 cop[tikv] or(and(eq(test.t.a, 1), eq(length(cast(test.t.b)), 1)), and(eq(test.t.b, 1), eq(length(cast(test.t.a)), 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")) + "Projection_4 1.60 root test.t.a, test.t.b", + "└─IndexMerge_9 0.00 root ", + " ├─IndexRangeScan_5(Build) 1.00 cop[tikv] table:t, index:a(a) range:[1,1], keep order:false, stats:pseudo", + " ├─IndexRangeScan_6(Build) 1.00 cop[tikv] table:t, index:b(b) range:[1,1], keep order:false, stats:pseudo", + " └─Selection_8(Probe) 0.00 cop[tikv] or(and(eq(test.t.a, 1), eq(length(cast(test.t.b)), 1)), and(eq(test.t.b, 1), eq(length(cast(test.t.a)), 1)))", + " └─TableRowIDScan_7 2.00 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("show warnings").Check(testkit.Rows()) } func (s *testIntegrationSerialSuite) TestIssue16407(c *C) { @@ -1330,10 +1334,10 @@ func (s *testIntegrationSerialSuite) TestIssue16407(c *C) { tk.MustExec("create table t(a int,b char(100),key(a),key(b(10)))") tk.MustQuery("explain select /*+ use_index_merge(t) */ * from t where a=10 or b='x'").Check(testkit.Rows( "Projection_4 19.99 root test.t.a, test.t.b", - "└─IndexMerge_9 0.02 root ", + "└─IndexMerge_9 0.04 root ", " ├─IndexRangeScan_5(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", " ├─IndexRangeScan_6(Build) 10.00 cop[tikv] table:t, index:b(b) range:[\"x\",\"x\"], keep order:false, stats:pseudo", - " └─Selection_8(Probe) 0.02 cop[tikv] eq(test.t.b, \"x\")", + " └─Selection_8(Probe) 0.04 cop[tikv] or(eq(test.t.a, 10), eq(test.t.b, \"x\"))", " └─TableRowIDScan_7 19.99 cop[tikv] table:t keep order:false, stats:pseudo")) tk.MustQuery("show warnings").Check(testkit.Rows()) tk.MustExec("insert into t values (1, 'xx')") @@ -2208,3 +2212,34 @@ func (s *testIntegrationSuite) TestIssue22105(c *C) { tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) } } + +func (s *testIntegrationSuite) TestIndexMergeTableFilter(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, b int, c int, d int, key(a), key(b));") + tk.MustExec("insert into t values(10,1,1,10)") + + tk.MustQuery("explain select /*+ use_index_merge(t) */ * from t where a=10 or (b=10 and c=10)").Check(testkit.Rows( + "Projection_4 10.01 root test.t.a, test.t.b, test.t.c, test.t.d", + "└─IndexMerge_9 0.02 root ", + " ├─IndexRangeScan_5(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", + " ├─IndexRangeScan_6(Build) 10.00 cop[tikv] table:t, index:b(b) range:[10,10], keep order:false, stats:pseudo", + " └─Selection_8(Probe) 0.02 cop[tikv] or(eq(test.t.a, 10), and(eq(test.t.b, 10), eq(test.t.c, 10)))", + " └─TableRowIDScan_7 19.99 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("select /*+ use_index_merge(t) */ * from t where a=10 or (b=10 and c=10)").Check(testkit.Rows( + "10 1 1 10", + )) + tk.MustQuery("explain select /*+ use_index_merge(t) */ * from t where (a=10 and d=10) or (b=10 and c=10)").Check(testkit.Rows( + "Projection_4 0.02 root test.t.a, test.t.b, test.t.c, test.t.d", + "└─IndexMerge_9 0.00 root ", + " ├─IndexRangeScan_5(Build) 10.00 cop[tikv] table:t, index:a(a) range:[10,10], keep order:false, stats:pseudo", + " ├─IndexRangeScan_6(Build) 10.00 cop[tikv] table:t, index:b(b) range:[10,10], keep order:false, stats:pseudo", + " └─Selection_8(Probe) 0.00 cop[tikv] or(and(eq(test.t.a, 10), eq(test.t.d, 10)), and(eq(test.t.b, 10), eq(test.t.c, 10)))", + " └─TableRowIDScan_7 19.99 cop[tikv] table:t keep order:false, stats:pseudo", + )) + tk.MustQuery("select /*+ use_index_merge(t) */ * from t where (a=10 and d=10) or (b=10 and c=10)").Check(testkit.Rows( + "10 1 1 10", + )) +} diff --git a/planner/core/stats.go b/planner/core/stats.go index ebe7e4f046417..fdfbdbe6c4f9f 100644 --- a/planner/core/stats.go +++ b/planner/core/stats.go @@ -557,16 +557,11 @@ func (ds *DataSource) buildIndexMergeOrPath(partialPaths []*util.AccessPath, cur indexMergePath := &util.AccessPath{PartialIndexPaths: partialPaths} indexMergePath.TableFilters = append(indexMergePath.TableFilters, ds.pushedDownConds[:current]...) indexMergePath.TableFilters = append(indexMergePath.TableFilters, ds.pushedDownConds[current+1:]...) - tableFilterCnt := 0 for _, path := range partialPaths { - // IndexMerge should not be used when the SQL is like 'select x from t WHERE (key1=1 AND key2=2) OR (key1=4 AND key3=6);'. - // Check issue https://github.com/pingcap/tidb/issues/22105 for details. + // If any partial path contains table filters, we need to keep the whole DNF filter in the Selection. if len(path.TableFilters) > 0 { - tableFilterCnt++ - if tableFilterCnt > 1 { - return nil - } - indexMergePath.TableFilters = append(indexMergePath.TableFilters, path.TableFilters...) + indexMergePath.TableFilters = append(indexMergePath.TableFilters, ds.pushedDownConds[current]) + break } } return indexMergePath diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index aca84f868983d..a31210b2402dc 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -1318,11 +1318,12 @@ { "SQL": "explain SELECT /*+ use_index_merge(t1)*/ COUNT(*) FROM t1 WHERE (key4=42 AND key6 IS NOT NULL) OR (key1=4 AND key3=6)", "Plan": [ - "StreamAgg_20 1.00 root funcs:count(Column#12)->Column#10", - "└─TableReader_21 1.00 root data:StreamAgg_9", - " └─StreamAgg_9 1.00 cop[tikv] funcs:count(1)->Column#12", - " └─Selection_19 10.00 cop[tikv] or(and(eq(test.t1.key4, 42), not(isnull(test.t1.key6))), and(eq(test.t1.key1, 4), eq(test.t1.key3, 6)))", - " └─TableFullScan_18 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo" + "StreamAgg_10 1.00 root funcs:count(1)->Column#10", + "└─IndexMerge_20 0.02 root ", + " ├─IndexRangeScan_16(Build) 10.00 cop[tikv] table:t1, index:i4(key4) range:[42,42], keep order:false, stats:pseudo", + " ├─IndexRangeScan_17(Build) 10.00 cop[tikv] table:t1, index:i1(key1) range:[4,4], keep order:false, stats:pseudo", + " └─Selection_19(Probe) 0.02 cop[tikv] or(and(eq(test.t1.key4, 42), not(isnull(test.t1.key6))), and(eq(test.t1.key1, 4), eq(test.t1.key3, 6)))", + " └─TableRowIDScan_18 19.99 cop[tikv] table:t1 keep order:false, stats:pseudo" ] } ]