动态裁切模式下,执行计划仍然显示partition:all

在开启分区表动态裁切的模式下,执行计划里面还是显示partition:all
复现步骤:
tidb版本:6.1.5

t1的表结构如下
CREATE TABLE t1 (
id int(11) DEFAULT NULL,
h_record int(11) DEFAULT NULL,
KEY id (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (100),
PARTITION p1 VALUES LESS THAN (200),
PARTITION p2 VALUES LESS THAN (300),
PARTITION p3 VALUES LESS THAN (400));
insert into t1 values(101,1),(201,2),(301,3),(399,4);

t2的表结构如下
CREATE TABLE t2 (
id int(11) DEFAULT NULL,
grade int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
insert into t2 values(101,0),(201,1),(301,2),(399,3);
analyze table t1;
analyze table t2;
set tidb_partition_prune_mode = ‘dynamic’;

mysql> explain select /*+ TIDB_INLJ(t1, t2) */ t1.id,t1.h_record from t1 join t2 on t1.id=t2.id where t2.grade = 0;
±--------------------------------±--------±----------±-----------------------±----------------------------------------------------------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
±--------------------------------±--------±----------±-----------------------±----------------------------------------------------------------------------------------------------------------------------+
| IndexJoin_12 | 0.01 | root | | inner join, inner:IndexLookUp_11, outer key:fqtest.t2.id, inner key:fqtest.t1.id, equal cond:eq(fqtest.t2.id, fqtest.t1.id) |
| ├─TableReader_17(Build) | 0.01 | root | | data:Selection_16 |
| │ └─Selection_16 | 0.01 | cop[tikv] | | eq(fqtest.t2.grade, 0), not(isnull(fqtest.t2.id)) |
| │ └─TableFullScan_15 | 8.00 | cop[tikv] | table:t2 | keep order:false, stats:pseudo |
| └─IndexLookUp_11(Probe) | 1.25 | root | partition:all | |
| ├─Selection_10(Build) | 1.25 | cop[tikv] | | not(isnull(fqtest.t1.id)) |
| │ └─IndexRangeScan_8 | 1.25 | cop[tikv] | table:t1, index:id(id) | range: decided by [eq(fqtest.t1.id, fqtest.t2.id)], keep order:false, stats:pseudo |
| └─TableRowIDScan_9(Probe) | 1.25 | cop[tikv] | table:t1 | keep order:false, stats:pseudo |
±--------------------------------±--------±----------±-----------------------±----------------------------------------------------------------------------------------------------------------------------+
8 rows in set (0.00 sec)

像这种都实现了分区动态裁切,为什么执行计划还是显示partition:all,是显示问题嘛,t1表不需要扫描所有的分区,按理来说只应该显示某个分区才对?

EXPLAIN SELECT t1.id,t1.h_record FROM t1 JOIN t2 ON t1.id=t2.id WHERE t2.id = 101;
这样写才行,你那样通过T2的grade过滤条件,和T1进行动态分区裁剪是同时进行的,然后两个表才进行join,并不会将t1的id条件带入T1的动态分区裁剪之中。


官方 也有相似的案例, 您可以看下

https://docs.pingcap.com/zh/tidb/stable/partition-pruning

官方的和您的相似度 还是很高的 。

1.EXPLAIN SELECT t1.id,t1.h_record FROM t1 JOIN t2 ON t1.id=t2.id WHERE t2.id = 101;
如果这么写的话,直接就可以select t1.id,t1.h_record FROM t1 WHERE t1.id = 101;
都没必要关联了吧
2.你那样通过T2的grade过滤条件,和T1进行动态分区裁剪是同时进行的,然后两个表才进行join,并不会将t1的id条件带入T1的动态分区裁剪之中。
我的理解是t1的id的取值范围是t2表的id传过来的,看执行计划就可以知道,t1是index join 里面的inner表,inner表的值都是outer表传过来的

分区裁剪的规则优化是在查询计划的生成阶段,对于执行阶段才能获取到过滤条件的场景,无法利用分区裁剪的优化。

能够做动态分区裁切,就是说明在执行计划的生成阶段,就做了这个优化

这种显示是合理的,因为在t1.id是关联条件并非过滤条件,在执行阶段才能确定,优化器并不知道这个值应该落在什么分区上,所有分区都有可能。显示all没问题。

这么讲的话我就可以理解了,虽然可以裁剪分区,其实执行计划生成的时候,还是不知道去哪个分区裁剪

显示partition:all 才是正常的,表示动态采集裁剪生效了,否则执行计划展示会有一堆,每个分区展示一次,然后一堆union。

为什么动态裁剪生效了以后,访问分区表,例如 explain select * from t1 where id < 150; 访问分区表的方式就不需要union all了,这是为啥?
这和动态裁剪有必然的关系嘛?

有啊,因为动态裁切的一个算子可以访问多个分区。静态裁切一个算子只能访问一个分区。所以静态的只能一堆union all拼接,动态的可以在一个算子里面展示多个分区标签。

懂了,

此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。