Skip to content

Commit 89cab6a

Browse files
authored
Planner: Run full partition pruning if convertToPointGet converted keys to SortKey (#59918)
close #59827
1 parent 046e83e commit 89cab6a

File tree

10 files changed

+376
-57
lines changed

10 files changed

+376
-57
lines changed

pkg/executor/builder.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5344,7 +5344,11 @@ func (b *executorBuilder) buildBatchPointGet(plan *plannercore.BatchPointGetPlan
53445344
b.inSelectLockStmt = false
53455345
}()
53465346
}
5347-
handles, isTableDual := plan.PrunePartitionsAndValues(b.ctx)
5347+
handles, isTableDual, err := plan.PrunePartitionsAndValues(b.ctx)
5348+
if err != nil {
5349+
b.err = err
5350+
return nil
5351+
}
53485352
if isTableDual {
53495353
// No matching partitions
53505354
return &TableDualExec{

pkg/executor/point_get.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ func (b *executorBuilder) buildPointGet(p *plannercore.PointGetPlan) exec.Execut
5555
return nil
5656
}
5757

58-
if p.PrunePartitions(b.ctx) {
59-
// no matching partitions
58+
isTableDual, err := p.PrunePartitions(b.ctx)
59+
if err != nil {
60+
b.err = err
61+
return nil
62+
}
63+
if isTableDual {
6064
return &TableDualExec{
6165
BaseExecutorV2: exec.NewBaseExecutorV2(b.ctx.GetSessionVars(), p.Schema(), p.ID()),
6266
numDualRows: 0,

pkg/planner/core/casetest/partition/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ go_test(
1010
],
1111
data = glob(["testdata/**"]),
1212
flaky = True,
13-
shard_count = 10,
13+
shard_count = 13,
1414
deps = [
1515
"//pkg/config",
1616
"//pkg/planner/util/coretestsdk",

pkg/planner/core/casetest/partition/partition_pruner_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,3 +524,113 @@ func TestRangeTimePruningExtract(t *testing.T) {
524524
runExtractTestCases(t, colType, extractTestCases)
525525
}
526526
}
527+
528+
func TestIssue59827(t *testing.T) {
529+
store := testkit.CreateMockStore(t)
530+
tk := testkit.NewTestKit(t, store)
531+
tk.MustExec("use test")
532+
tk.MustExec("CREATE TABLE `t` (" +
533+
"`a` varchar(150) NOT NULL," +
534+
"`b` varchar(100) NOT NULL," +
535+
"`c` int NOT NULL DEFAULT '0'" +
536+
",PRIMARY KEY (`a`,`b`) /*T![clustered_index] CLUSTERED */" +
537+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" +
538+
" PARTITION BY LIST COLUMNS(`b`)" +
539+
"(PARTITION `p0` VALUES IN ('0')," +
540+
"PARTITION `p1` VALUES IN ('1')," +
541+
"PARTITION `p2` VALUES IN ('2'))")
542+
543+
tk.MustExec("insert into t values ('a','1',1),('b','1',1),('b', '2', 2)")
544+
tk.MustExec("set @@session.tidb_partition_prune_mode = 'static'")
545+
tk.MustQuery("select * from t where a = 'b' and b IN('1','2')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
546+
tk.MustQuery("select * from t where a = 'b' and (b IN ('1','2'))").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
547+
tk.MustQuery("select * from t where a = 'b' and (b = '2' or b = '1')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
548+
tk.MustExec("set @@session.tidb_partition_prune_mode = 'dynamic'")
549+
tk.MustQuery("select * from t where a = 'b' and b IN('1','2')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
550+
tk.MustQuery("select * from t where a = 'b' and (b IN ('1','2'))").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
551+
tk.MustQuery("select * from t where a = 'b' and (b = '2' or b = '1')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
552+
553+
tk.MustQuery("select * from t where a = 'b' and b = '2'").Check(testkit.Rows("b 2 2"))
554+
tk.MustQuery("select * from t where a = 'b' and b = '1'").Check(testkit.Rows("b 1 1"))
555+
tk.MustQuery("select * from t where a = 'b' and (b = '2')").Check(testkit.Rows("b 2 2"))
556+
tk.MustQuery("select * from t where a = 'b' and (b = '1')").Check(testkit.Rows("b 1 1"))
557+
tk.MustQuery("select * from t where a = 'b' and b = ('2')").Check(testkit.Rows("b 2 2"))
558+
tk.MustQuery("select * from t where a = 'b' and b = ('1')").Check(testkit.Rows("b 1 1"))
559+
tk.MustQuery("explain select * from t where a = 'b' and b = '2'").CheckContain("partition:p2")
560+
tk.MustQuery("explain select * from t where a = 'b' and (b = '2')").CheckContain("partition:p2")
561+
562+
tk.MustExec("PREPARE stmt FROM 'select * from t where a = ? and b = ?'")
563+
tk.MustExec("SET @a = 'b', @b = '2'")
564+
tk.MustQuery("EXECUTE stmt USING @a, @b").Check(testkit.Rows("b 2 2"))
565+
tk.MustExec("SET @a = 'a', @b = '1'")
566+
tk.MustQuery("EXECUTE stmt USING @a, @b").Check(testkit.Rows("a 1 1"))
567+
tk.MustExec("DEALLOCATE PREPARE stmt")
568+
tk.MustExec(`PREPARE stmt FROM "select * from t where a = 'b' and b = ?"`)
569+
tk.MustExec("SET @b = '2'")
570+
tk.MustQuery("EXECUTE stmt USING @b").Check(testkit.Rows("b 2 2"))
571+
tk.MustExec("SET @b = '1'")
572+
tk.MustQuery("EXECUTE stmt USING @b").Check(testkit.Rows("b 1 1"))
573+
tk.MustExec("DEALLOCATE PREPARE stmt")
574+
575+
tk.MustExec("PREPARE stmt FROM 'select * from t where a = ? and (b = ?)'")
576+
tk.MustExec("SET @a = 'b', @b = '2'")
577+
tk.MustQuery("EXECUTE stmt USING @a, @b").Check(testkit.Rows("b 2 2"))
578+
tk.MustExec("SET @a = 'a', @b = '1'")
579+
tk.MustQuery("EXECUTE stmt USING @a, @b").Check(testkit.Rows("a 1 1"))
580+
tk.MustExec("DEALLOCATE PREPARE stmt")
581+
tk.MustExec(`PREPARE stmt FROM "select * from t where a = 'b' and b = (?)"`)
582+
tk.MustExec("SET @b = '2'")
583+
tk.MustQuery("EXECUTE stmt USING @b").Check(testkit.Rows("b 2 2"))
584+
tk.MustExec("SET @b = '1'")
585+
tk.MustQuery("EXECUTE stmt USING @b").Check(testkit.Rows("b 1 1"))
586+
tk.MustExec("DEALLOCATE PREPARE stmt")
587+
}
588+
589+
func TestIssue59827KeyPartitioning(t *testing.T) {
590+
store := testkit.CreateMockStore(t)
591+
tk := testkit.NewTestKit(t, store)
592+
tk.MustExec("use test")
593+
tk.MustExec("CREATE TABLE `t` (" +
594+
"`a` varchar(150) NOT NULL," +
595+
"`b` varchar(100) NOT NULL," +
596+
"`c` int NOT NULL DEFAULT '0'" +
597+
",PRIMARY KEY (`b`) /*T![clustered_index] CLUSTERED */" +
598+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" +
599+
" PARTITION BY KEY(`b`) PARTITIONS 13")
600+
601+
tk.MustExec("insert into t values ('a','3',3),('b','1',1),('b', '2', 2),('xX','xX',10),('Yy','Yy',11)")
602+
tk.MustExec("set @@session.tidb_partition_prune_mode = 'static'")
603+
tk.MustQuery("select * from t where (b IN ('Xx','yY'))").Sort().Check(testkit.Rows("Yy Yy 11", "xX xX 10"))
604+
tk.MustQuery("select * from t where b IN('1','2')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
605+
tk.MustQuery("select * from t where (b IN ('1','2'))").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
606+
tk.MustQuery("select * from t where b = '2' or b = '1'").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
607+
tk.MustQuery("select * from t where (b = '2' or b = '1')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
608+
tk.MustExec("set @@session.tidb_partition_prune_mode = 'dynamic'")
609+
tk.MustQuery("select * from t where (b IN ('Xx','yY'))").Sort().Check(testkit.Rows("Yy Yy 11", "xX xX 10"))
610+
tk.MustQuery("select * from t where b IN('1','2')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
611+
tk.MustQuery("select * from t where (b IN ('1','2'))").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
612+
tk.MustQuery("select * from t where b = '2' or b = '1'").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
613+
tk.MustQuery("select * from t where (b = '2' or b = '1')").Sort().Check(testkit.Rows("b 1 1", "b 2 2"))
614+
}
615+
616+
func TestIssue59827RangeColumns(t *testing.T) {
617+
store := testkit.CreateMockStore(t)
618+
tk := testkit.NewTestKit(t, store)
619+
tk.MustExec("use test")
620+
tk.MustExec("CREATE TABLE `t` (" +
621+
"`a` varchar(150) COLLATE utf8mb4_general_ci NOT NULL," +
622+
"`b` varchar(100) COLLATE utf8mb4_general_ci NOT NULL," +
623+
"`c` int NOT NULL DEFAULT '0'," +
624+
"PRIMARY KEY (`a`,`b`) /*T![clustered_index] CLUSTERED */" +
625+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" +
626+
" PARTITION BY RANGE COLUMNS(`b`)" +
627+
"(PARTITION `p0` VALUES LESS THAN ('1')," +
628+
"PARTITION `p1` VALUES LESS THAN ('2')," +
629+
"PARTITION `p2` VALUES LESS THAN ('3'))")
630+
631+
tk.MustExec("insert into t values ('a','1',1),('b','1',1),('b', '2', 2)")
632+
tk.MustQuery("select * from t where a = 'b' and b = '2'").Check(testkit.Rows("b 2 2"))
633+
tk.MustQuery("select * from t where a = 'b' and (b = '2')").Check(testkit.Rows("b 2 2"))
634+
tk.MustQuery("explain select * from t where a = 'a' and b = '2'").CheckContain("partition:p2")
635+
tk.MustQuery("explain select * from t where a = 'a' and (b = '2')").CheckContain("partition:p2")
636+
}

pkg/planner/core/find_best_task.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,11 @@ func findBestTask4LogicalDataSource(lp base.LogicalPlan, prop *property.Physical
15421542
canConvertPointGet = false
15431543
}
15441544
if canConvertPointGet && len(path.Ranges) > 1 {
1545+
// if LIST COLUMNS/RANGE COLUMNS partitioned, and any of the partitioning columns are string based
1546+
// and having non-binary collations, then we currently cannot support BatchPointGet,
1547+
// since the candidate.path.Ranges already have been converted to SortKey, meaning we cannot use it
1548+
// for PartitionLookup/PartitionPruning currently.
1549+
15451550
// TODO: This is now implemented, but to decrease
15461551
// the impact of supporting plan cache for patitioning,
15471552
// this is not yet enabled.

0 commit comments

Comments
 (0)