一本国产数据库性能优化书,值得读吗?
前言
新年尹始,笔者就收到了金仓社区麦麦邮寄过来的新年礼物,一本精美的日历 📅,以及这本《金仓数据库 KingbaseES 性能优化》。趁着元旦假期,把整本书从头到尾认真读完,说实话,这是一本超出我预期的技术书。
介绍
整本书共九章,第一章讲的是性能优化的方法论,其中有一句话让我印象非常深刻:
在处理性能问题之前首先确认这是不是一个真正的性能问题。
这句话看似简单,但在真实项目中却经常被忽略。我见过太多新手 DBA 或工程师,一听到"数据库慢了",就开始慌乱操作,改参数、改 SQL、重启服务,忙得不可开交,却从未想过:这是不是一个可量化的问题?问题到底发生在业务侧,还是系统侧?性能优化的目标,从来不是让数据库看起来很忙,而是让业务可以稳定、可预期地运行。从这个角度看,这本书在一开始就把“方向”摆正了。
第二章介绍了性能优化基础,其中提到 KingbaseES 实现了 Global plan cache(目前仅支持 Simple Protocal),这一点在我看来,是一个非常务实的改进,在 OLTP 场景下,并发高、SQL 模式稳定,执行计划生成阶段的开销并不低。如果执行计划可以跨会话复用,那么对于大量结构相同的 SQL,请求响应时间会有非常明显的改善。而在社区版中,执行计划缓存基本仍停留在会话级别,共享计划缓存一直是个"老大难"的问题,仅有一个许久没有维护的插件方案:https://github.com/rjuju/pg_shared_plans。
第四章是我认为工程含量非常高的一章,介绍了数据库性能诊断能力。KingbaseES 实现了一整套完善的可观测能力
•KWR:历史快照报告•KDDM:基于 KWR 的优化建议报告•KDR DIFF:变更导致的性能问题回溯与分析•KSH:活跃会话历史追溯
不少 Oracle 老用户都吐槽过 PostgreSQL 在可观测性方面"工具零散、拼插件、缺历史",KingbaseES 至少在工程化落地上,向前迈了一大步。相信在碰到性能问题的时候,我们会更加得心应手,游刃有余。
第五章提出了一个非常值得借鉴的概念 ——时间模型,旨在明确各子系统对系统性能的影响,基于时间模型,构建多维度的分析框架,帮助定位性能问题的根本原因。通过拆解一次 SQL 请求在各阶段的耗时,将性能问题自顶向下地拆分为:
1.建立连接是否慢(进程模型 / 是否需要连接池)2.SQL 本身是否慢(等待资源 vs 真正计算慢)3.返回数据是否过多(网络吞吐,服务器编程、结果集控制)4.等待事件与系统瓶颈定位
其次,此章节还介绍了一些典型的等待事件,比如我们的老熟人 buffer_content (在高并发 + 大 shared_buffers 下是公认热点)、lock_manager 等,对于 wal_insert 等待事件 (是的,经常被 openGauss 喷的点,18 版本中有了很大的改善,无锁优化,减少了很多必须加锁的路径),KingbaseES 提供了一个 enable_xlog_insert_lock_free 的参数,可以消除 wal_insert 等待事件,提升性能,不过对于系统有一定的要求。
第六章介绍了 SQL 语句优化基础,根据介绍,书中提到的 KingbaseES 版本暂时未体现向量化执行引擎,主要是传统的火山模型,或许是面向更多的是 TP 场景。
第七章介绍的是 SQL 查询执行计划,此处略过。
第八章介绍的优化 SQL 执行计划,根据介绍,KingbaseES 提供了SQL 优化建议器 sys_sqltune,不过根据描述,支持的改写场景还比较少:UNION 转 UNION ALL、DETELE 转 TRUNCATE,隐式类型转换使用索引。其次,在查询优化器的逻辑优化阶段,针对一些特殊场景也进行了加强,由 kdb_rbo 插件提供,此处就直接引用原文吧:
1.针对 SQL 语句中存在多个 (NOT) EXISTS 子查询,并且子查询之间存在包含和被包含的关系,可以将这些子查询合并,生成新的 (NOT) EXISTS 子查询,减少对子查询中相同表的扫描、连接等操作2.如果 SQL 中存在重复的子查询或多个子查询中存在同样的表达式,或者多个 UNION ALL 分支中存在共同访问的表,则可以将这些共同的部分转换为 CTE,减少对公共表的访问次数或公共表连接操作,提升 SQL 语句的执行性能3.当一个带有 UNION 操作的子查询参与连接操作时,可以将连接条件下推到 UNION 连接的各个子查询中,从而通过 Nestloop 参数化路径的方式提升 SQL 性能4.SELECT 子句中,count(distinct XX) 通常的执行方式是先排序去掉重复值,然后进行统计计算。KingbaseES 的优化器对 SELECT 子句中 count(distinct XX) 的执行方式进行了优化,如果需要进行计数的列有特别多的重复值,有参数 kdb_rbo.attribute_distinct_value_threshold 控制,默认是 0.1,即数据的重复度在 90% 以上,则引入分组特性来提升 SQL 的性能。相当于将 SQL 自动改写:select count(distinct o_clerk) from orders; → select count(o_clerk) from (select o_clerk from orders group by o_clerk);
其次,KingbaseES 还实现了位图索引,对于索引属性基数较小的情形,位图索引则比较合适。在本章节的最后,还介绍了一个黑科技 —— 查询映射,将一个查询映射为另一个查询,相信很多朋友都遇到过陈年屎山代码无法修改的情况,你让他去改写 SQL 以优化性能那是万万不可能的,牵一发而动全身,出了问题谁也担不起责任,这个时候查询映射的作用就体现出来了,数据库内部根据定义会自动维护一套映射规则,实现碰到 A 语句自动改写为 B 语句,给这个功能点赞 👍🏻。
第九章描述的是如何编写高效的 SQL 语句,比如 OR 语句的改写,之前笔者也介绍过:SQL 优化之 OR 子句改写、DB Killer 标量子查询、IN 和 EXISTS 的改写 告别 SubPlan 循环!PostgreSQL 17 相关子查询性能直线飙升 等等。
目前,PostgreSQL 优化器对 SQL 中的 OR 子句过滤条件的优化能力较为有限。如果 OR 子句中的过滤条件仅涉及一张表,且所有过滤条件上均具备适当的索引,则优化器会为此类场景生成一个 BitmapOr 的 Index Path。
最后一章则是介绍了一些建模方面的最佳实践,比如分区表的设计,数据类型的选择等等。总而言之,后续章节更多集中在 SQL 优化、执行计划改写和一些工程层面的增强。
小结
作为一名长期在 PostgreSQL / GP 生态里打滚,对国产数据库保持理性怀疑,但愿意认真看、认真评价的老油条,总体来看,这本书虽然是围绕 KingbaseES 展开的,但其中大量的性能分析方法、排障思路和工程实践,并不局限于某一个数据库产品。不必带着"站队"的心态去读,把它当成一本性能方法论 + 工程实践集合,反而能收获更多。