我去年出差略多,于是在路上把目前主要的两本PostgreSQL书大概翻了翻,做了些笔记,谈点个人看法。
以下简称PG,反正都懂。文内对PG有误解或说错的地方还请批评指正。
第一部分笔记,基于《PostgreSQL修炼之道》一书为主。该书唐成著,2015年出版。此时PG的最新版本应该是9.4。本文亦有基于其他资料。
注:以下“唐老师”指唐成老师,“张老师”指张文升老师。
1. AUTOCOMMIT关键字
事务自动提交模式关键字AUTOCOMMIT,只能大写,小写不行,大小写混合也不行。
唐老师: AUTOCOMMIT,是指psql默认autocommit是on的,我见过的多数人喜欢自动提交。如果觉得这样不安全,可以在.psqlrc中一次性配置好,就不同改了。
点评:这个是小事,但用起来稍微有点不太方便。
2. 什么时候开始表分区
建议当表大小超过PG可用的物理内存时,就开始做表分区。不太了解这个建议是怎么得来的...
唐老师:这个表具体多大该建分区,不同人有不同的认识。通常如果超过内存大小,cache的作用就很弱了。所以超过了物理内存大小,一定应该分区了。
实际上,目前机器的内存都比较大,如512G,实际上表远远没有到512G大小就应该建分区。我个人认为超过32GB,就应该建成分区表。
点评:个人看法,表分区并不是必要的,要综合考虑这个表的宽度(行平均长度)、事务活跃度、数据分布情况,不一而同。
3. 最大事务ID不能超过INT32
事务ID不能超过4字节(32-bit)整数,而且还存在回卷的问题。
唐老师:关于事物ID 32bit的问题,实际上不是把32bit改成64bit就解决问题了。个人认为如果只是改成64bit,实际上没有太大用处。
PG比较保守,32bit虽然可以到20亿,但一般参数设置到2亿,就开始vacuum了。实际中还不如直接把autovacuumfreezemax_age从2亿设置成8亿。
这本质还是一个垃圾回收的问题,就像java的垃圾回收,永远有人说需要优化。
另外,vacuum目前对单个表不能并发,当表比较大时,会导致vacuum很长时间。
张老师:这个历史遗留问题,不过autovacuum近几年的改进可以很大程度缓解事务回滚的问题,但还是治标不治本。
有商业公司将事务号改为int64了,但改动比较多,所以一直没有合并到master,主要依靠运维人员解决,当然,int64是根本的方案,应该包含在以后的发行版中。
点评:虽然通过调整优化回收机制可以缓解这个问题,但我还是觉得升级到64位INT会更好一些。
4. 主从复制功能
最最最要命的,PG直到9.0(2010年发布)才开始支持主从复制,而MySQL在2000年发布3.23版本时就支持了,早了10年,但B乎上有人说MySQL 8.0终于追上PG 9.6的主要功能。
唐老师:关于主备库,实际上不是说9.0之前搭建不了主备库,也可以搭建。就是延迟太大,不方便。当然也可以自己写程序来实现减少延迟,但总之就是不方便。这也是别人说PG太学院派的原因,这么重要的功能不早点加上。
点评:对于互联网,一年的变化就已经非常大了,主从复制这个功能晚了十年才推出,的确很不应该。
5. 版本管理机制
看了下PG的发版模式,大感惊讶。前阵子,同天同时发布12.2、11.7、10.12、9.6.17、9.5.21 和9.4.26共6个版本。再看release notes,以9.0系列为例,基本上每个月都会发布个小版本。这么频繁发版,产品路线规划和版本管理挺堪忧的,做过产品和项目管理的同学们应该有此体会。
这里,其实还有个花边小料。PG发版其实是被各个大商业公司控制的,这些公司想加啥功能,不想加啥功能,都是他们几个巨头说了算。为什么维护那么多大版本,也是因为巨头各自的利益平衡。我道听途说的哈,不对这个料的真假负责。
唐老师:版本的发布,这是误解。PG是固定每个季度发一个小版本,发这个季度发现的问题都修掉。而一般小版本基本不加功能,只修bug。而发现一个bug,这个bug可能在不同的大版本中都是同一个问题。通常所以12.2、11.7、10.12等等这些实际上是一个发布。
PG一年才发布一个大版本,相当于把功能累积一年,才发布,所以发布并不频繁。一般小版本升级很容易,只需要换二进制程序就可以了。另小版本修复的bug,大多是一些比较偏门的bug,有一些用户有时小版本也懒得升级。
巨头们控制,我的认知是这是阴谋论,不存在这个问题。只是PG内核组的人,比较保守,如果你对代码做了大量的修改,内核组的人认为无法review代码和测试发现你的代码的bug,可能就不接受。小修小改,他们最容易接受。大的功能需要拆很多次提交才行。如PG的并行功能,实际上在9.5版本,一些并行的代码就提交进入了,但这些代码只是一些框架和支持代码,不提供任何 可以使用的功能。然后9.6在作出一些并行的功能。后面在慢慢完善这个功能。
张老师:关于版本发布的问题,PG的支持版本是5年,你看到的更新版本是针对不同的LTS的release,这个比较好理解。不过PG是被大公司控制的好像不合理,可以订阅PG官方的邮件了解一下合并到master的情况。
点评:个人还是对PG的发版机制保留意见,对个人用户来说,可能可以避免了被迫升级新版本的“痛苦”,但从项目管理角度说,并行太多计划,相信也会对项目质量有一定影响,见仁见智吧。
6. 第三方插件升级
PG有很多功能需要安装插件,如果做版本升级时候,这些插件也要升级适配。比较要命的是,这些插件大多不是原生的,是第三方提供的,升级适配性比较差。MySQL也有第三方引擎,不过几个主流的引擎都是有比较给力的公司/团队在维护,跟随新版本方面还算及时。
唐老师:PG插件。如果PG插件没有与PG的SQL执行器或优化器等核心功能绑定以及在数据库中创建自己的元数据表,通常是可以做到二进制兼容的。如你自己只是几个bit位运算的函数。这是升级是比较方便的,只要把你的插件的.so拷贝到新版本上就可以了。但如果与版本有关了,升级就有一些麻烦。另一些第三方的差距,质量也是层次不齐,使用的时候需要注意。
点评:个人感觉PG的第三方插件比MySQL更多些,管理起来也不容易。
7. 表分区实现方式
据说在PG11前,表分区是通过触发器插件实现的,这个感觉有点诧异...
唐老师:分区,实际上PG11的之前的分区都是通过很早之前的 表继承来实现的。
而在PG10之前,需要手工建触发器或创建规则来辅助完成分区。这些分区存在一个问题,一方面是触发器,性能会导致插入性能低(当然看你的应用,如果对性能没有这么敏感,其实也没有问题),另就是当分区很多时,而表继承是可以让各个分区的表结构不一样的,这样每个分区都有独立元数据,硬解析的代价与与分区数成线性关系,导致分区很多时,硬解析代价变的很大(硬解析达到1毫秒以上)。
另关于分区,实际上表继承的功能,在某些场景下,用很多的一些作用。如在线的腾挪数据。用作分区,只是表继承的一个方面。当然,如果PG开始就没有表继承的功能,那么表分区的功能估计早都完善了。因为有表继承的功能导致全面的分区功能没有这么急迫,所以拖到了PG12版本才彻底完善好了。
当然在PG9.X时代,有第三方的插件pg_pathman,用这个插件实现分区功能也非常好,功能也很强大。但因为社区核心组的人都是一些很严谨的人,而pg_pathman的代码量比较大,同时修改的都是很核心的部分,所以没有把pg_pathman的代码直接合并到内核中,而是慢慢根据pg_pathman的原理,在经历了PG10、11、12后,才把分区表的功能给完善了。
张老师:PG10之前的表分区是该吐槽,用继承表搞分区不止麻烦,性能还不好。不过PG12的分区表确实有一些可圈可点的地方,可以关注。另外,PG的分区表不支持逻辑复制,这点也不好。
点评:不知道PG铁粉会不会说“yeah,PG的分区比MySQL的更牛逼?”
8. PG没有UNDO LOG
都知道PG著名的"问题",即不记录undo log,而是在表空间中记录每条数据的N个历史版本以实现MVCC,但也带来了后续的vacumn行为,不知道这个"问题"现在有无更好的解决办法。
唐老师: 无undo log。实际上目前vacuum只要合理的配置,并不是什么严重的问题。但目前小白很多,不会做合理的配置,导致这方面的问题较多。对于高并发的数据库,就需要DBA的用心维护。但大家总是想,不需要深入了解这个问题,对PG的默认参数不做修改,就让PG数据库能马上支持高并发的业务场景,目前看这个问题无解。PG9.6或更前面的版本,默认创建出来的数据库的默认参数,有一些在我们一般使用中是不太合理的。到后续版本的PG,如PG10,创建出来的默认参数就合理了一些。当然这可能也有一些历史原因,一些参数默认都是按机械硬盘来设置的。一些加快vacuum同时又要减少对线上业务影响的参数默认没有打开。
点评:PG的MVCC实现机制的确独树一帜,在恢复回滚时确实有优势,但伴随的vacumn问题始终是个阴影。
另一本由谭峰和张文升主笔的《PostgreSQL实战》笔记以后找机会再聊。
受限于个人对PG的认识水平,本文仅涉及到几个很小的方面。本文也并不表示我对PG的态度就是负面的,PG也是个伟大的数据库,MySQL亦是如此,各有所爱吧,止战,各自发力造福技术社区才是正道。
全文完
本文首发 https://mp.weixin.qq.com/s/_UWUHyvBf7Uz5_d_f20Bqg