diff --git a/cmd/explaintest/r/explain_easy.result b/cmd/explaintest/r/explain_easy.result index 214e51b366de1..c2c61bf79b58e 100644 --- a/cmd/explaintest/r/explain_easy.result +++ b/cmd/explaintest/r/explain_easy.result @@ -124,11 +124,12 @@ Projection 10000.00 root eq(test.t1.c2, test.t2.c2)->Column#11 └─Apply 10000.00 root CARTESIAN left outer join ├─TableReader(Build) 10000.00 root data:TableFullScan │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo - └─Projection(Probe) 1.00 root test.t2.c1, test.t2.c2 - └─IndexLookUp 1.00 root limit embedded(offset:0, count:1) - ├─Limit(Build) 1.00 cop[tikv] offset:0, count:1 - │ └─IndexRangeScan 1.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo - └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo + └─Limit(Probe) 1.00 root offset:0, count:1 + └─Projection 1.00 root test.t2.c1, test.t2.c2 + └─IndexLookUp 1.00 root + ├─Limit(Build) 1.00 cop[tikv] offset:0, count:1 + │ └─IndexRangeScan 1.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo + └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo explain format = 'brief' select * from t1 order by c1 desc limit 1; id estRows task access object operator info Limit 1.00 root offset:0, count:1 diff --git a/cmd/explaintest/r/explain_easy_stats.result b/cmd/explaintest/r/explain_easy_stats.result index e76b0d4d233a6..8305dfa929e2b 100644 --- a/cmd/explaintest/r/explain_easy_stats.result +++ b/cmd/explaintest/r/explain_easy_stats.result @@ -106,11 +106,12 @@ Projection 1999.00 root eq(test.t1.c2, test.t2.c2)->Column#11 └─Apply 1999.00 root CARTESIAN left outer join ├─TableReader(Build) 1999.00 root data:TableFullScan │ └─TableFullScan 1999.00 cop[tikv] table:t1 keep order:false - └─Projection(Probe) 1.00 root test.t2.c1, test.t2.c2 - └─IndexLookUp 1.00 root limit embedded(offset:0, count:1) - ├─Limit(Build) 1.00 cop[tikv] offset:0, count:1 - │ └─IndexRangeScan 1.25 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true - └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo + └─Limit(Probe) 1.00 root offset:0, count:1 + └─Projection 1.00 root test.t2.c1, test.t2.c2 + └─IndexLookUp 1.00 root + ├─Limit(Build) 1.00 cop[tikv] offset:0, count:1 + │ └─IndexRangeScan 1.25 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true + └─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo explain format = 'brief' select * from t1 order by c1 desc limit 1; id estRows task access object operator info Limit 1.00 root offset:0, count:1 diff --git a/executor/partition_table_test.go b/executor/partition_table_test.go index 34066a301bff4..84bf7513a6514 100644 --- a/executor/partition_table_test.go +++ b/executor/partition_table_test.go @@ -2403,6 +2403,42 @@ func (s *partitionTableSuite) TestDirectReadingWithAgg(c *C) { } } +func (s *partitionTableSuite) TestIssue24636(c *C) { + tk := testkit.NewTestKitWithInit(c, s.store) + tk.MustExec("create database test_issue_24636") + tk.MustExec("use test_issue_24636") + + tk.MustExec(`CREATE TABLE t (a int, b date, c int, PRIMARY KEY (a,b)) + PARTITION BY RANGE ( TO_DAYS(b) ) ( + PARTITION p0 VALUES LESS THAN (737821), + PARTITION p1 VALUES LESS THAN (738289) + )`) + tk.MustExec(`INSERT INTO t (a, b, c) VALUES(0, '2021-05-05', 0)`) + tk.MustQuery(`select c from t use index(primary) where a=0 limit 1`).Check(testkit.Rows("0")) + + tk.MustExec(` + CREATE TABLE test_partition ( + a varchar(100) NOT NULL, + b date NOT NULL, + c varchar(100) NOT NULL, + d datetime DEFAULT NULL, + e datetime DEFAULT NULL, + f bigint(20) DEFAULT NULL, + g bigint(20) DEFAULT NULL, + h bigint(20) DEFAULT NULL, + i bigint(20) DEFAULT NULL, + j bigint(20) DEFAULT NULL, + k bigint(20) DEFAULT NULL, + l bigint(20) DEFAULT NULL, + PRIMARY KEY (a,b,c) /*T![clustered_index] NONCLUSTERED */ + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin + PARTITION BY RANGE ( TO_DAYS(b) ) ( + PARTITION pmin VALUES LESS THAN (737821), + PARTITION p20200601 VALUES LESS THAN (738289))`) + tk.MustExec(`INSERT INTO test_partition (a, b, c, d, e, f, g, h, i, j, k, l) VALUES('aaa', '2021-05-05', '428ff6a1-bb37-42ac-9883-33d7a29961e6', '2021-05-06 08:13:38', '2021-05-06 13:28:08', 0, 8, 3, 0, 9, 1, 0)`) + tk.MustQuery(`select c,j,l from test_partition where c='428ff6a1-bb37-42ac-9883-33d7a29961e6' and a='aaa' limit 0, 200`).Check(testkit.Rows("428ff6a1-bb37-42ac-9883-33d7a29961e6 9 0")) +} + func (s *partitionTableSuite) TestIdexMerge(c *C) { if israce.RaceEnabled { c.Skip("exhaustive types test, skip race test") diff --git a/planner/core/exhaust_physical_plans.go b/planner/core/exhaust_physical_plans.go index a0c0072e94a33..0d8b183a6900a 100644 --- a/planner/core/exhaust_physical_plans.go +++ b/planner/core/exhaust_physical_plans.go @@ -2061,6 +2061,7 @@ func (lt *LogicalTopN) getPhysLimits(prop *property.PhysicalProperty) []Physical Count: lt.Count, Offset: lt.Offset, }.Init(lt.ctx, lt.stats, lt.blockOffset, resultProp) + limit.SetSchema(lt.Schema()) ret = append(ret, limit) } return ret diff --git a/planner/core/task.go b/planner/core/task.go index d3b8b84d78ead..c1b925451ca1b 100644 --- a/planner/core/task.go +++ b/planner/core/task.go @@ -1127,6 +1127,16 @@ func (p *PhysicalLimit) sinkIntoIndexLookUp(t task) bool { return false } } + + // If this happens, some Projection Operator must be inlined into this Limit. (issues/14428) + // For example, if the original plan is `IndexLookUp(col1, col2) -> Limit(col1, col2) -> Project(col1)`, + // then after inlining the Project, it will be `IndexLookUp(col1, col2) -> Limit(col1)` here. + // If the Limit is sunk into the IndexLookUp, the IndexLookUp's schema needs to be updated as well, + // but updating it here is not safe, so do not sink Limit into this IndexLookUp in this case now. + if p.Schema().Len() != reader.Schema().Len() { + return false + } + // We can sink Limit into IndexLookUpReader only if tablePlan contains no Selection. ts, isTableScan := reader.tablePlan.(*PhysicalTableScan) if !isTableScan { diff --git a/planner/core/testdata/integration_suite_out.json b/planner/core/testdata/integration_suite_out.json index 77aa5b1494da7..72d5c968d7468 100644 --- a/planner/core/testdata/integration_suite_out.json +++ b/planner/core/testdata/integration_suite_out.json @@ -14,11 +14,12 @@ { "SQL": "explain format = 'brief' select * from tbl use index(idx_b_c) where b > 1 order by b desc limit 2,1", "Plan": [ - "Projection 1.00 root test.tbl.a, test.tbl.b, test.tbl.c", - "└─IndexLookUp 1.00 root limit embedded(offset:2, count:1)", - " ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3", - " │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc", - " └─TableRowIDScan(Probe) 1.00 cop[tikv] table:tbl keep order:false, stats:pseudo" + "Limit 1.00 root offset:2, count:1", + "└─Projection 3.00 root test.tbl.a, test.tbl.b, test.tbl.c", + " └─IndexLookUp 3.00 root ", + " ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3", + " │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc", + " └─TableRowIDScan(Probe) 3.00 cop[tikv] table:tbl keep order:false, stats:pseudo" ] }, {