PostgreSQL 13在2020年9月正式发布,带来了很多新特性和性能改进。我们公司在第一时间就把生产环境升级到了PostgreSQL 13,在使用过程中踩了不少坑,也积累了一些实战经验。本文总结了我们在使用PostgreSQL 13过程中遇到的典型问题和解决方法,包括升级注意事项、性能调优、新特性使用、运维管理等方面。如果你也在用PostgreSQL或者准备升级到13版本,希望这篇文章能帮你少走弯路。
一、为什么升级到PostgreSQL 13
先说说我们为什么要升级到PostgreSQL 13吧。
我们公司一直用PostgreSQL作为主力数据库,从9.6版本一路升级上来。PostgreSQL 13发布之后,我们看了一下新特性,觉得有几个点非常吸引人,所以决定尽快升级。
PostgreSQL 13的主要新特性包括:
- 索引性能提升:B-tree索引的空间利用率提高了,重复索引值的存储更高效
- 并行查询增强:支持并行VACUUM、并行创建索引等
- 增量排序:在已经排序的数据集上进行排序时性能更好
- 分区表增强:支持BEFORE行级触发器,分区裁剪更智能
- 扩展功能增强:新增一些内置函数和操作符
- 性能监控增强:新增更多的监控视图和统计信息
其中最让我们心动的是B-tree索引的空间利用率提升。我们有几个大表,索引占了很大的空间,如果能减少索引的空间占用,不仅能节省存储成本,还能提高缓存命中率,提升查询性能。
另外,并行VACUUM也是我们非常期待的功能。我们有几个非常大的表,每次VACUUM都要跑很久,影响业务。并行VACUUM可以大大缩短VACUUM的时间。
于是我们在测试环境验证了一周之后,就把生产环境升级到了PostgreSQL 13。升级之后整体效果不错,但是也踩了不少坑。下面就把这些经验分享给大家。
二、升级过程中的坑
升级是第一个大坑。虽然PostgreSQL的升级工具已经比较成熟了,但是实际操作中还是会遇到各种问题。
坑1:pg_upgrade升级失败
我们用的是pgupgrade工具来做升级,从PostgreSQL 12升级到13。按照官方文档的步骤操作,但是在执行pgupgrade的时候失败了,报错说有几个扩展不兼容。
排查之后发现,是我们安装了几个第三方扩展,这些扩展在PostgreSQL 13上还没有对应的版本,导致升级失败。
解决方法是,先在旧版本上删除这些不兼容的扩展,升级完成之后再重新安装新版本的扩展。但是删除扩展之前要确认这些扩展没有被业务依赖,否则会影响业务。
还有一个方法是用逻辑复制的方式升级,先搭建一个PostgreSQL 13的从库,用逻辑复制同步数据,等数据同步完成之后再切换主从。这种方式对业务影响小,但是操作比较复杂。
所以升级之前一定要检查所有已安装的扩展,确认它们在新版本上是否有对应的版本。如果有不兼容的扩展,要提前想好处理方案。
坑2:升级后统计信息丢失导致性能下降
升级完成之后,我们发现有几个查询的性能突然下降了,原来几百毫秒的查询现在要跑好几秒。
排查之后发现,是因为pg_upgrade不会复制统计信息,新版本的数据库没有表的统计信息,导致优化器选择了错误的执行计划。
解决方法很简单,升级之后立即对所有表执行ANALYZE,重新生成统计信息。执行完ANALYZE之后,查询性能就恢复了。
所以升级之后一定要记得执行ANALYZE,最好是在升级脚本里加上这一步,避免忘记。我们后来把升级脚本完善了,升级完成之后自动执行ANALYZE,就再也没有遇到这个问题了。
坑3:配置参数变化
PostgreSQL 13有一些配置参数发生了变化,有的参数被废弃了,有的参数默认值变了。升级之后如果还用旧的配置文件,可能会有问题。
我们遇到的情况是,有一个参数在PostgreSQL 13中被废弃了,但是我们的postgresql.conf里还设置了这个参数,导致数据库启动的时候有警告。虽然不影响运行,但是看着不舒服。
还有一个参数的默认值变了,导致升级之后行为和之前不一样,影响了一个业务功能。
解决方法是,升级之前仔细阅读新版本的发布说明,了解所有参数的变化。升级之后用新的默认配置文件,然后根据需要修改参数,不要直接用旧的配置文件。
三、性能调优的经验
升级完成之后,我们对PostgreSQL 13做了一些性能调优,这里分享一些经验。
1. 利用B-tree索引的空间优化
PostgreSQL 13对B-tree索引做了优化,对于有重复值的索引,空间占用大大减少。但是这个优化只对新建的索引生效,已有的索引不会自动优化。
所以升级之后,我们对那些有大量重复值的索引做了REINDEX,重建索引之后,空间占用减少了30%到50%,效果非常明显。
比如我们有一个订单表,有一个状态字段的索引,状态只有几个值,重复率非常高。重建索引之后,这个索引的大小从2G减少到了800M,减少了60%的空间。
而且索引变小之后,缓存命中率提高了,查询性能也有一定的提升。
所以升级到PostgreSQL 13之后,建议对大表的索引做一次REINDEX,充分利用新版本的索引优化。但是REINDEX的时候要注意,会锁表,影响业务,最好在业务低峰期操作,或者用REINDEX CONCURRENTLY。
2. 并行VACUUM的使用
PostgreSQL 13支持并行VACUUM,对于大表来说,可以大大缩短VACUUM的时间。
并行VACUUM由两个参数控制:maxparallelmaintenanceworkers(并行维护操作的最大工作进程数)和vacuumcost_limit(VACUUM的成本限制)。
我们把maxparallelmaintenance_workers设置为4,然后对一个500G的大表执行VACUUM,原来需要跑3个多小时,现在只需要40多分钟,提升非常明显。
但是要注意,并行VACUUM会占用更多的IO和CPU资源,在业务高峰期不要执行,最好在维护窗口操作。另外,并行VACUUM只对表本身有效,对索引的VACUUM还是串行的。
还有一点,autovacuum不会使用并行VACUUM,只有手动执行的VACUUM才会使用并行。所以对于特别大的表,可以在维护窗口手动执行并行VACUUM。
3. 增量排序的优化
PostgreSQL 13新增了增量排序功能,当输入数据已经部分排序的时候,排序操作会更高效。这个功能默认是开启的,由参数enableincrementalsort控制。
我们有一个查询,是按日期分组之后再按某个字段排序,之前的执行计划是先做全量排序,性能不好。升级到13之后,优化器自动选择了增量排序,查询性能提升了2倍多。
但是增量排序也不是所有场景都有效,它只在输入数据已经部分排序的情况下才有优势。如果输入数据完全无序,增量排序反而可能更慢。
如果发现某个查询的性能因为增量排序而下降,可以用SET enableincrementalsort = off来关闭这个功能,或者调整查询语句。
4. 分区表的性能优化
PostgreSQL 13对分区表做了很多优化,包括更智能的分区裁剪、支持BEFORE行级触发器等。
我们有一个按时间分区的大表,之前查询的时候,如果查询条件包含时间范围,PostgreSQL会裁剪掉不需要的分区。但是在PostgreSQL 12及之前的版本中,分区裁剪有一些限制,比如某些函数的条件无法裁剪。升级到13之后,分区裁剪更智能了,很多之前无法裁剪的查询现在都能正确裁剪了。
比如我们有一个查询条件是WHERE create_time >= now() - interval '7 days',在PostgreSQL 12中,因为now()是volatile函数,无法做分区裁剪,会扫描所有分区。升级到13之后,优化器可以在执行的时候计算出具体的时间范围,然后做分区裁剪,查询性能提升了很多。
所以如果你用了分区表,升级到13之后会有明显的性能提升。
四、新特性使用中的坑
PostgreSQL 13有很多新特性,但是在使用过程中也遇到了一些坑。
坑4:genrandomuuid()函数的问题
PostgreSQL 13内置了genrandomuuid()函数,可以生成随机UUID,不需要再安装pgcrypto扩展了。这是一个很方便的新特性。
但是我们在使用的时候遇到了一个问题。我们有一个表,主键是UUID类型,默认值用的是genrandomuuid()。升级到13之后,我们把原来的uuidgeneratev4()改成了genrandomuuid()。
但是后来发现,用genrandomuuid()生成的UUID,在做索引扫描的时候性能比uuidgeneratev4()差一些。原因是genrandomuuid()生成的UUID是完全随机的,而uuidgeneratev4()生成的UUID有一定的顺序性。完全随机的UUID在插入的时候会导致索引页分裂更频繁,影响插入性能。
如果你对插入性能要求很高,可以考虑用uuidgeneratev4()或者有序UUID。如果只是普通的使用场景,genrandomuuid()完全够用,而且更方便。
坑5:扩展的兼容性问题
升级到PostgreSQL 13之后,有些扩展需要重新编译或者升级版本。我们遇到的情况是,pgstatstatements扩展升级之后,视图的字段有变化,导致我们的监控脚本出错了。
还有一些第三方扩展,升级之后行为有变化,需要调整使用方式。
所以升级之后,要检查所有使用的扩展,确认它们在新版本上的行为是否有变化。监控脚本、业务代码中用到扩展的地方都要测试一下。
五、运维管理的经验
1. 监控指标的变化
PostgreSQL 13新增了一些监控视图和统计信息,比如pgstatprogressvacuum可以查看VACUUM的进度,pgstatprogresscreate_index可以查看创建索引的进度。
这些新的监控视图非常有用,可以让我们更清楚地了解数据库的运行状态。我们把这些新指标加入了监控系统,运维效率提升了不少。
比如之前执行VACUUM的时候,只能看到进程在运行,不知道进度如何,也不知道还要跑多久。现在有了pgstatprogress_vacuum,可以实时看到VACUUM的进度,包括扫描了多少页面、清理了多少死元组等,非常方便。
2. 备份和恢复
升级之后,备份策略也要相应调整。pgdump的版本要和数据库版本一致,用旧版本的pgdump备份新版本的数据库可能会有问题。
我们用的是pgbasebackup做物理备份,升级之后备份脚本也要用新版本的pgbasebackup。另外,升级之后要做一次完整的备份,确保备份是可用的。
还有一点,升级之后的数据库不能用旧版本的pg_restore来恢复,一定要用新版本的工具。
3. 日常维护
PostgreSQL 13的日常维护和之前的版本差不多,主要是VACUUM、ANALYZE、REINDEX这些。但是因为有了并行VACUUM和更高效的索引,维护的效率提升了不少。
我们的维护策略是:每天凌晨执行autovacuum,每周对大表手动执行一次并行VACUUM,每月对索引做一次REINDEX。升级到13之后,维护时间大大缩短了,对业务的影响也更小了。
六、一些实用的建议
最后给大家一些使用PostgreSQL 13的实用建议。
第一,升级之前一定要在测试环境充分测试。把生产环境的数据导入测试环境,跑一下典型的业务查询,看看性能有没有变化,有没有兼容性问题。不要直接在生产环境升级,风险太大。
第二,升级之后立即执行ANALYZE,重新生成统计信息。这一步非常重要,很多性能问题都是因为统计信息丢失导致的。
第三,对大表的索引做一次REINDEX,利用新版本的索引空间优化。但是要在业务低峰期操作,避免影响业务。
第四,仔细阅读新版本的发布说明,了解所有的变化,包括新特性、参数变化、不兼容的地方等。这样才能充分利用新特性,避免踩坑。
第五,监控要跟上。把新版本新增的监控指标加入监控系统,及时发现和处理问题。
第六,做好备份。升级之前做一次完整备份,升级之后也要做一次完整备份。确保出了问题可以回滚。
七、写在最后
PostgreSQL 13是一个非常优秀的版本,带来了很多实用的新特性和性能改进。升级之后,我们的数据库性能有了明显提升,运维效率也提高了不少。
但是升级和使用过程中确实会遇到一些坑,需要我们认真对待。只要做好充分的准备,仔细测试,遇到问题及时排查,大部分问题都能顺利解决。
PostgreSQL社区非常活跃,每个版本都会带来很多改进。作为使用者,我们要保持学习的心态,及时了解新版本的特性,合理地使用新功能,让数据库更好地为业务服务。
希望我们的踩坑经验和实战总结能帮到正在使用或者准备升级到PostgreSQL 13的朋友。如果有什么问题,欢迎在评论区交流讨论。
用一句话结束本文:"数据库的稳定运行,来自于对细节的极致追求。"愿每一个DBA都能驾驭PostgreSQL,让它为业务创造更大的价值。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录