planner: avoid using index_merge when there are multiple table filters (#22122)
This commit is contained in:
@ -1429,13 +1429,10 @@ 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(
|
||||
"Projection_4 1.60 root test.t.a, test.t.b",
|
||||
"└─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"))
|
||||
}
|
||||
|
||||
func (s *testIntegrationSerialSuite) TestIssue16407(c *C) {
|
||||
@ -2358,3 +2355,40 @@ func (s *testIntegrationSuite) TestIssue22040(c *C) {
|
||||
c.Assert(errors.Cause(err), FitsTypeOf, expression.ErrOperandColumns)
|
||||
}
|
||||
}
|
||||
|
||||
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...))
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,6 +426,9 @@ func (ds *DataSource) generateIndexMergeOrPaths() {
|
||||
}
|
||||
if len(partialPaths) > 1 {
|
||||
possiblePath := ds.buildIndexMergeOrPath(partialPaths, i)
|
||||
if possiblePath == nil {
|
||||
return
|
||||
}
|
||||
|
||||
accessConds := make([]expression.Expression, 0, len(partialPaths))
|
||||
for _, p := range partialPaths {
|
||||
@ -554,8 +557,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...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,5 +242,11 @@
|
||||
"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)"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
15
planner/core/testdata/integration_suite_out.json
vendored
15
planner/core/testdata/integration_suite_out.json
vendored
@ -1348,5 +1348,20 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user