分区表的利与弊

1、表太大的危害

autovacuum 垃圾版本回收、freeze 冻结xid号操作都是有粒度的: 一个表、一个索引只能同时有1个进程对其进行回收和冻结工作(同一个表的多个索引可以并行)。多个不同的表(包括不同的分区)可以有多个vacuum进程并行执行。
(未来希望单个表(单个分区)也能实现多进程并行垃圾回收。

  1. 垃圾回收慢, 可能跟不上产生垃圾的速度(尤其是频繁产生事务的业务系统), 导致表、索引膨胀,导致IO变大。
  2. 表变大, 索引自然也变大, 垃圾扫描时垃圾版本可能超出内存, 使得索引可能需要被多次扫描。我们可以通过命令 vacuum verbose table 看到详细信息 index scan被扫描多次。
    这时候如果autovacuum_work_mem为-1,需要加大 maintenance_work_mem 。
  3. 单个表freeze的操作变久, 在极端情况可能导致xid耗尽(例如数据实时同步系统每秒都产生大量事务id), 数据库需要停库进入单用户模式执行freeze降低年龄后才能正常使用。
  4. freeze的操作密度变大,表非常大, 完成1个表的freeze就会产生大量的wal日志的IO,如果是小表还能通过表级别配置参数来进行freeze错峰, 同时可能导致standby延迟,复制冲突等。
  5. 由于单表(单个最底层分区)的逻辑备份恢复无法并行, 大表的逻辑备份恢复耗时变长。 除了时长问题, 另一个问题是长时间逻辑备份恢复可能会导致膨胀,因为这个过程阻止了vacuum进程回收工作。
  6. 由于单表(单个最底层分区)只能对应到某一个表空间, 表空间又会对应到某个目录, 某个目录对应到某个文件系统,所以单表很大的时候可能大于某个文件系统, 而将表拆小后能放到不同的表空间, 不同的文件系统。这对于不同业务系统可能产生的数据量一定要做好前期规划。

所以要定期清理数据, 防止表膨胀. 例如最常见的, 按时间清理历史数据。

2、没有分区的危害

没有分区, 那么当delete清理数据, delete产生大量wal日志, 导致从库延迟, 同时还需要垃圾回收产生二次数据文件和WAL IO, 而且delete清理大量数据属于事务, 长事务还会引发膨胀隐患.这就形成了恶性循环。
建议分区: 使用时间分区, 可以直接drop或truncate分区. 几乎不产生wal日志, 也不需要垃圾回收, 速度非常快。

3、多个块设备的场景, 没有分区, 单表高频率访问时, 无法达到充分利用块设备的效果

如果你的数据库环境有多块盘, 通常1个文件系统最多对应1个块设备, 所以一个非分区表无法充分利用块设备的并行吞吐能力。

对数据库透明的其他解决方案: 可以用卷管理来实现多个块设备组合成条带, 用逻辑卷照样能利用多个块设备的并行吞吐。

然而分区过多也会有一些问题

1: 分区过多, 对于一些老版本的数据库, 优化器在生成path后才会分区裁剪, 分区过多会使得生成执行计划非常耗时, 对于执行很快的SQL, 性能损耗尤为突出。

2: relcache缓存暴增,如果业务使用了长连接, 假使每个会话在会话的整个生命周期内访问过每个子分区的话, 同样会导致relcache占用内存过多, 使得每个会话占有大量内存, 最终触发OOM。

3: 当SQL没有利用分区字段作为条件时, 需要访问所有分区, 分区过多会导致执行计划时间超长, 同时可能某些更优的访问路径就无法获得(例如某些情况下hashagg, hashjoin, merge join等可能无法支持)

分两种情况, 假如有性能很好的SSD的情况.

1、高频更新、删除、插入

这种表产生的垃圾多, 需要频繁回收垃圾, 否则会膨胀. 而且要保证垃圾回收的效率比产生垃圾快, 因此推荐单个分区不能太大,。能够满足不因垃圾回收不及时而导致膨胀为宜。 例如: 3000-5000万条。.

2、append only(只能insert), 少量更新

以不产生影响业务性能(抖动)的wal风暴为宜, 这种表的分区可以适当大一点, 例如3-5亿。

posted @ 2023-05-19 15:19  KINGBASE研究院  阅读(151)  评论(0编辑  收藏  举报