From 493d6942a33a646485888bafb8e0257388182d4e Mon Sep 17 00:00:00 2001 From: HuaiyuXu <391585975@qq.com> Date: Thu, 31 Dec 2020 13:39:49 +0800 Subject: [PATCH] cherry pick #22122 to release-4.0 Signed-off-by: ti-srebot --- planner/core/integration_test.go | 44 +++++++++++++++ planner/core/stats.go | 14 +++++ .../core/testdata/integration_suite_in.json | 18 ++++++ .../core/testdata/integration_suite_out.json | 55 +++++++++++++++++++ 4 files changed, 131 insertions(+) diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index cb847486a49a0..298a07235ae86 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -1185,12 +1185,19 @@ 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( +<<<<<<< HEAD "IndexMerge_9 1.60 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) 1.60 cop[tikv] eq(length(cast(test.t.a)), 1), eq(length(cast(test.t.b)), 1)", " └─TableRowIDScan_7 2.00 cop[tikv] table:t keep order:false, stats:pseudo")) tk.MustQuery("show warnings").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")) +>>>>>>> f1805f3de... planner: avoid using index_merge when there are multiple table filters (#22122) } func (s *testIntegrationSerialSuite) TestIssue16407(c *C) { @@ -1626,3 +1633,40 @@ func (s *testIntegrationSuite) TestUpdateMultiUpdatePK(c *C) { tk.MustExec(`UPDATE t m, t n SET m.a = m.a + 1, n.b = n.b + 10`) tk.MustQuery("SELECT * FROM t").Check(testkit.Rows("2 12")) } + +func (s *testIntegrationSuite) TestIssue22105(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec(`CREATE TABLE t1 ( + key1 int(11) NOT NULL, + key2 int(11) NOT NULL, + key3 int(11) NOT NULL, + key4 int(11) NOT NULL, + key5 int(11) DEFAULT NULL, + key6 int(11) DEFAULT NULL, + key7 int(11) NOT NULL, + key8 int(11) NOT NULL, + KEY i1 (key1), + KEY i2 (key2), + KEY i3 (key3), + KEY i4 (key4), + KEY i5 (key5), + KEY i6 (key6) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin`) + + var input []string + var output []struct { + SQL string + Plan []string + } + s.testData.GetTestCases(c, &input, &output) + for i, tt := range input { + s.testData.OnRecord(func() { + output[i].SQL = tt + output[i].Plan = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows()) + }) + tk.MustQuery(tt).Check(testkit.Rows(output[i].Plan...)) + } +} diff --git a/planner/core/stats.go b/planner/core/stats.go index 919f7c768b4af..d5dae9fb1c4b8 100644 --- a/planner/core/stats.go +++ b/planner/core/stats.go @@ -338,6 +338,13 @@ func (ds *DataSource) generateIndexMergeOrPaths() { } if len(partialPaths) > 1 { possiblePath := ds.buildIndexMergeOrPath(partialPaths, i) +<<<<<<< HEAD +======= + if possiblePath == nil { + return + } + +>>>>>>> f1805f3de... planner: avoid using index_merge when there are multiple table filters (#22122) accessConds := make([]expression.Expression, 0, len(partialPaths)) for _, p := range partialPaths { accessConds = append(accessConds, p.AccessConds...) @@ -460,8 +467,15 @@ 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 len(path.TableFilters) > 0 { + tableFilterCnt++ + if tableFilterCnt > 1 { + return nil + } indexMergePath.TableFilters = append(indexMergePath.TableFilters, path.TableFilters...) } } diff --git a/planner/core/testdata/integration_suite_in.json b/planner/core/testdata/integration_suite_in.json index 351da83bf8a83..73b7ac24d4042 100644 --- a/planner/core/testdata/integration_suite_in.json +++ b/planner/core/testdata/integration_suite_in.json @@ -163,5 +163,23 @@ "select approx_percentile(a, 10*10) from t", "select approx_percentile(a, 50) from t group by b order by b" ] +<<<<<<< HEAD +======= + }, + { + "name": "TestConvertRangeToPoint", + "cases": [ + "explain select * from t0 where a > 1 and a < 3 order by b limit 2", + "explain select * from t1 where a >= 2 and a <= 2 and b = 2 and c > 2", + "explain select * from t2 where a >= 2.5 and a <= 2.5 order by b limit 2", + "explain select * from t3 where a >= 'a' and a <= 'a' and b = 'b' and c > 'c'" + ] + }, + { + "name": "TestIssue22105", + "cases": [ + "explain SELECT /*+ use_index_merge(t1)*/ COUNT(*) FROM t1 WHERE (key4=42 AND key6 IS NOT NULL) OR (key1=4 AND key3=6)" + ] +>>>>>>> f1805f3de... planner: avoid using index_merge when there are multiple table filters (#22122) } ] \ No newline at end of file diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index d9ba53089c67f..afa2d02250e96 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -889,5 +889,60 @@ ] } ] +<<<<<<< HEAD +======= + }, + { + "Name": "TestConvertRangeToPoint", + "Cases": [ + { + "SQL": "explain select * from t0 where a > 1 and a < 3 order by b limit 2", + "Plan": [ + "Limit_11 2.00 root offset:0, count:2", + "└─IndexReader_21 2.00 root index:Limit_20", + " └─Limit_20 2.00 cop[tikv] offset:0, count:2", + " └─IndexRangeScan_19 2.50 cop[tikv] table:t0, index:a(a, b) range:[2,2], keep order:true, stats:pseudo" + ] + }, + { + "SQL": "explain select * from t1 where a >= 2 and a <= 2 and b = 2 and c > 2", + "Plan": [ + "IndexReader_6 0.33 root index:IndexRangeScan_5", + "└─IndexRangeScan_5 0.33 cop[tikv] table:t1, index:a(a, b, c) range:(2 2 2,2 2 +inf], keep order:false, stats:pseudo" + ] + }, + { + "SQL": "explain select * from t2 where a >= 2.5 and a <= 2.5 order by b limit 2", + "Plan": [ + "Limit_11 2.00 root offset:0, count:2", + "└─IndexReader_21 2.00 root index:Limit_20", + " └─Limit_20 2.00 cop[tikv] offset:0, count:2", + " └─IndexRangeScan_19 2.00 cop[tikv] table:t2, index:a(a, b) range:[2.5,2.5], keep order:true, stats:pseudo" + ] + }, + { + "SQL": "explain select * from t3 where a >= 'a' and a <= 'a' and b = 'b' and c > 'c'", + "Plan": [ + "IndexReader_6 0.33 root index:IndexRangeScan_5", + "└─IndexRangeScan_5 0.33 cop[tikv] table:t3, index:a(a, b, c) range:(\"a\" \"b\" \"c\",\"a\" \"b\" +inf], keep order:false, stats:pseudo" + ] + } + ] + }, + { + "Name": "TestIssue22105", + "Cases": [ + { + "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" + ] + } + ] +>>>>>>> f1805f3de... planner: avoid using index_merge when there are multiple table filters (#22122) } ]