TIDB 分区裁剪为什么能提高检索速度?

分区表或者是不分区的表的数据以及索引都是划分为Region分布到不同节点上的,并且同一个节点的全部Region都是存在一个rocksdb之中,Region的元数据也都是存在PD之上,依据索引直接查询和使用分区裁剪再进行索引查询感觉是没有区别的,都是先在PD定位到Region,之后再在Region内进行kv查询,PD定位Region的过程感觉也是一样的,只是带有分区的key里面加上了分区id,如果是这样的话,那么分区裁剪为什么能加快检索速度呢?感觉都是在PD kv一次查到Region,Region再kv一次查到数据。

如果这样想对的话,意外着TIDB完全淡化表的概念,所有表的数据和索引都是混在一起存在rocksdb里面的(虽然不同表在不同Region,但是Region也都是存在同一个rocksdb实例),那是不是意味着一个表很大,会导致其他小表检索也很慢,毕竟数据和索引都是存在如同一个rocksdb实例的。

在没有分区裁剪的情况下,如果执行一个查询语句,TiDB 可能需要扫描整个表的所有分区,即使其中大部分分区的数据并不满足查询条件。这会导致大量的无效数据被加载到内存中,增加了 I/O 开销和计算资源的使用。

而分区裁剪的作用就是在查询执行过程中,根据查询条件判断哪些分区的数据可能满足条件,然后只扫描这些分区,忽略不满足条件的分区。这样可以大大减少需要加载的数据量,降低 I/O 操作的次数,提高查询的执行效率。

我觉得文档的第一句就说明了为什么提高,因为扫描基数小了。

有一个优化叫做“分区裁剪”,它基于一个非常简单的概念:不需要扫描那些匹配不上的分区。

https://docs.pingcap.com/zh/tidb/stable/partitioned-table#分区裁剪

我这里不考虑没有索引的情况,没有索引的情况下确实可以扫描更少的数据,但线上查询可能不能靠全表扫描定位数据,那有索引的情况下,是不是没有太大区别,如果是传统单机数据库确实会因为分区键直接定位到某个分区,单个分区的索引也很小,从而提高检索速度,但是在tidb中普通表或者分区表的索引都会被切分成多个Region,那么基于索引的查找其实就是先去PD基于key定位Region,再到索引对应的Region基于key定位主键,整个过程感觉有没有分区是没有区别的,都是两次kv查找,有分区的那种无非就是key里面带了分区id,但是感觉kv查找时应该不会因为这点提高性能

分区表在tidb中最大作用是删除数据可以通过删除分区实现,速度很快。查询等作用确实效果一般般

我目前也感觉分区主要的意义是分区数据单独进行管理,还有就是通过分区打散初期的写入热点,但是文档确实又说了分区裁剪可以加快查找速度,所以我很疑惑。我觉得关键点是不同分区是否在物理层面实现了隔离,如果物理层面就是多个文件,单个分区肯定会加快查找速度,但是我看整个架构Region只是个逻辑概念,数据都是存在一个rocksdb实例里的,感觉完全不会提高查找速度,甚至会在查询条件不包含分区键的情况下降低查找速度。
但我确实看一些文章又看到一个在包含分区键下查找性能更好的例子,我怀疑我是哪里理解错了,是不是有哪一步会因为分区键的存在而加速?

简单而言,就是在逻辑优化的时候就已经确定了只扫描哪些分区,可以避免扫描一些不必要扫描的分区。

分区裁剪可以明显降低需要查询的数据量,特别是大表

更精准的扫描数据,扫描更少的行数,速度上肯定会有不小的提升

tidb的分区表的二级索引是跟随分区一起建的,如果能够使用分区裁剪的话,也能裁剪到对应的分区索引,速度应该也不算慢,问题是条件无分区,用不到分区裁剪的时候,由于tidb的分区表的二级索引不支持全局索引,每次都要全扫描所有的二级索引分区,这个效率反而不如传统单机数据库的全局索引。

1 个赞

如果不能确定扫描哪些分区,比如可以使用一个非主键索引,是否分区表的效率不如普通表?我记得早期版本里是无法在每个分区内使用索引。

感谢,我很认可您的观点,但我还有一点问题需要再确认下,就是假如条件中包含分区,然后走二级索引的时候分区真的能起到裁剪的作用吗,因为不同表和不同分区的数据都是混着存在同一个kv内部的,包括各个Region的元数据,也就是说走索引时其实不会先定位到一个分区,然后再在这个分区内部走一个比较小的索引,仍然是会在全局kv进行查找,只不过k里包含了分区键。整体而言就是分区只是个逻辑概念,不同分区的数据和索引还是混在一个大kv里面的,从这个角度看我觉得命中分区对走二级索引完全没有帮助,或者就是我理解的有问题,分区还是会对数据的物理分布产生影响,比如单独的kv实例(相当于更小的索引),或者尽量分布在不同节点,您怎么看待这点

分区不是逻辑概念
普通表有一个唯一id,kv内部的key是表id+数据主键。
分区表的key里面多分区键值

SELECT START_KEY, TIDB_DECODE_KEY(START_KEY),t.PARTITION_ID FROM information_schema.tikv_region_status t WHERE table_name=‘XXX’
and t.DB_NAME=‘XXXX’
and t.IS_INDEX=0
and t.IS_PARTITION=1

你可以用这个语句看看分区表和普通表的key构成

我明白分区表的key是带分区键的,但是这些key都是存在同一个大的kv数据库的,并不是每个分区有一个单独的实例,即使key带上分区键感觉也不会提高kv查找的速度

我的理解tidb的kv是按key有顺序存储,没有分区key顺序是按表主键排的,有分区是按分区加主键,也就是可以把一个分区的key排一起

好的,我现在理解在二级索引不包含分区键,但条件中还包含分区条件的情况下确实有一定效果,但假如二级索引本身就包含分区键的情况下应该是基本没有区别的

早期版本不清楚,我们用的是V6.5.4版本,分区里是可以使用索引的,不过目前这个版本目前还有的一个问题就是分区表的统计信息收集有点问题,仅TiDB自动收集会出现分区统计信息收集不完善或者过期的问题。不确定后面的版本有没有修复分区表统计信息收集的问题。

tidb不支持分区表全局索引,索引也是加分区键分区的

7.6.0我测了修复了