最近处理了一个生产环境数据库性能问题折腾了几天最后靠金仓 KingbaseES 的 KSHKingbaseES Shell生成的性能优化报告找到了突破口。这工具平时不太起眼关键时刻是真的顶比盲猜 SQL 慢在哪、参数该调哪个靠谱太多。所以想把这次用 KSH 做性能诊断和调优的完整思路整理出来给正在跟 KingbaseES 性能问题缠斗的朋友一个参考。先说下背景。这套 KingbaseES 数据库支撑的是一个典型的业务系统高峰期并发查询一上来数据库服务器的 CPU 使用率直接飙到 90% 以上部分核心业务的响应时间从几十毫秒退化到秒级。系统不是不能用就是慢得让人难受业务方天天催压力全在 DBA 这边。刚开始的时候团队里也有人提议直接改数据库参数比如把 shared_buffers 调大一点、work_mem 调高一点但这种操作属于盲调改完有没有效果全靠运气而且数据库参数不是拍脑袋就能定的改不好反而会引入新的问题。我的思路是先拿到一份完整的性能体检报告搞清楚系统到底慢在哪是 SQL 的问题还是内存配置的问题或者是 IO 层面有瓶颈。这时候 KSH 的性能优化报告功能就派上用场了。1. KSH 性能优化报告先搞清楚它是干什么的1.1 KSH 与性能报告的真实关系KSH 在 KingbaseES 里是一个客户端命令行工具类似 PostgreSQL 的 psql、Oracle 的 sqlplus平时主要用于执行 SQL 语句、管理数据库对象。但它的价值不止于此它还集成了一系列运维诊断能力性能优化报告就是其中一个非常核心的功能模块。通过 KSH 来生成性能报告本质上是在数据库运行期间采集一组快照数据然后基于这些快照数据自动生成一份多维度的诊断报告。这份报告里包含的信息非常丰富涵盖数据库实例的运行概况、等待事件分布、SQL 执行统计、内存使用情况、IO 表现、数据库配置参数等。相当于给数据库做了一次全身体检把各个器官的健康状况都量化出来方便 DBA 判断哪里出了问题。说实话第一次用这个工具生成报告的时候我是有一点意外的。我原本以为它就是简单地把一些系统视图的数据导出来实际看了报告之后发现里面有不少数据是经过加工和计算的不是直接能看出来的原始数值。比如缓存命中率、共享内存使用趋势、Top SQL 的 resource 消耗占比这些都是有现成统计逻辑的省了我自己写 SQL 去统计的时间。1.2 什么时候应该想到用 KSH 报告不是所有性能问题都需要上性能报告工具。比如一个简单的 SQL 全表扫描导致慢查询直接看执行计划就能定位一条 SQL 锁等待问题用系统视图查一下锁信息也能解决。但以下几类情况性能报告的价值会体现得非常明显系统整体变慢但定位不到具体是哪个环节出了问题SQL 看起来都不算特别离谱但整体响应就是不行。优化了某几个 Top SQL 之后整体性能提升不明显怀疑瓶颈不在 SQL 层面而是在内存、IO 或参数配置上。数据库参数被人动过或者版本升级之后性能出现退化需要一份客观数据来判断当前配置是否合理。业务高峰期过后需要对数据库做一次复盘搞清楚资源消耗在哪些环节为后续容量规划提供依据。我这次遇到的情况就属于第一种系统整体变慢但单个 SQL 拿出来看都不算特别过分。把我逼到墙角之后我决定用 KSH 生成一份正式的性能优化报告从全局视角慢慢排查。1.3 生成报告前的基础准备在用 KSH 生成报告之前有些准备工作是必不可少的尤其是权限和快照点的选择这两个环节直接影响报告的数据质量和参考价值。权限方面执行性能报告相关的命令需要一个拥有足够权限的数据库用户我这边直接用具备 dba 角色的高权限账号来操作。如果你只有普通用户权限可能会遇到权限不足的报错这一点要先找管理员确认。快照点选择是个容易忽略的细节。性能报告的数据是基于快照时间点采集的两次快照之间的数据变化就是分析的基础。如果是诊断性能问题建议在问题复现的窗口期取样。比如业务高峰期是上午十点到十一点那就在十点前做一个快照十一点后再做一个快照让报告覆盖整个问题时间区间。如果快照做在低谷期报告呈现的可能是一片太平根本没有参考价值。我这次的做法是先在问题高峰期前一小时登录数据库确保会话连接正常然后准备手工创建快照确保两个快照点能精准覆盖问题时段。如果系统已经开启了自动快照那也要确认自动快照的间隔和保留策略是否合理避免关键时段的快照被清理掉。2. 从报告里找出核心瓶颈一份报告重点看什么报告生成之后信息量会很大如果眉毛胡子一把抓很容易看花了眼。我总结了一套自己的阅读顺序按照这个顺序去看能比较快地锁定问题方向。核心顺序是先看实例概览评估整体健康度再看等待事件找系统层面的瓶颈然后看 SQL 统计筛选真正有问题的 SQL最后结合内存和 IO 数据判断是否需要调整参数配置。2.1 实例概览判断整体健康度实例概览部分会列出一系列关键的运行指标包括数据库运行时间、事务提交量、回滚量、缓存命中率、共享内存使用情况等。这一块不需要逐个深挖重点看几个关键指标是否在合理区间。缓存命中率是我首先关注的指标。这个数值反映了数据库从内存中直接获取数据的比例如果命中率长期低于 95%说明大量查询需要从磁盘读取数据IO 压力会比较大内存配置可能需要调整。我这次看到的缓存命中率是在可接受范围的说明问题可能不在数据缓存上。另一个值得关注的是事务回滚量。如果回滚量异常偏高说明应用层可能存在逻辑问题比如大量事务因为异常被回滚这不仅浪费资源还会引发锁竞争。我看到当时的事务回滚量处于正常范围基本排除了这个方向的嫌疑。2.2 等待事件分析定位系统瓶颈的关键等待事件是性能报告里含金量最高的部分之一。数据库在执行过程中会话经常需要等待某些资源就绪比如等待磁盘 IO、等待锁释放、等待网络传输等。这些等待事件按类型和耗时统计之后能非常直观地反映出系统的瓶颈点在哪里。我在报告里重点看了等待事件的总耗时和占比分布。比较常见的等待事件一般有几类磁盘 IO 相关等待比如等数据文件读取、等 WAL 日志刷盘。这类等待占比高说明存储系统可能跟不上。锁相关等待比如行锁、表锁、事务锁。这类等待占比高说明存在锁竞争可能有长事务或者锁粒度问题。CPU 相关等待表现为大量时间消耗在 CPU 计算上而不是等待资源。这类情况往往跟 SQL 执行效率低下有关。网络相关等待比如客户端与应用服务器之间的数据传输等待。我这次看到的报告中等待事件排在最前面的是一类 IO 相关等待耗时占比接近一半。同时 CPU 使用率持续处于高位说明系统在 IO 和 CPU 两个方向都存在压力。这个组合特征指向了一个可能的方向存储 IO 性能不足加上部分 SQL 执行计划不够高效导致 CPU 也在大量空转。2.3 Top SQL 统计找出真正拖后腿的查询等待事件能指方向但要解决问题最终得落到具体的 SQL 上。报告里的 SQL 统计部分会按照不同的维度排序比如执行时间最长的、执行次数最多的、读写数据量最大的、缓冲区命中率最低的。我一般会重点关注两类 SQL一类是单次执行时间特别久的另一类是执行频率特别高、单次不算慢但累计耗时大的。当时报告里显示的 Top SQL 让我比较意外排在前面的几条 SQL 看起来都有索引按道理不应该这么慢。于是我把其中一条拿出来单独做执行计划分析结果发现问题出在了统计信息不准确上优化器选择了一个不合适的执行路径导致扫描了大量无效数据。这也解释了为什么 CPU 使用率高——数据库在做无谓的数据扫描和比较运算。2.4 内存与 IO 数据验证参数配置是否合理报告里关于内存和 IO 的部分主要用来验证参数配置是否合理。我重点关注几个内存参数的实际使用情况包括 shared_buffers、work_mem、maintenance_work_mem 等。从报告数据看shared_buffers 的当前配置和实际使用情况基本匹配缓冲区的命中率也正常不存在明显的容量不足问题。IO 部分的数据给我留下的印象更深刻。从报告里的 IO 等待耗时和存储吞吐数据来看当前存储设备的性能表现确实不够理想尤其是在大量离散读取的场景下IO 延迟明显偏高。这和前面等待事件的分析结果是对得上的。到这里整个问题的轮廓就比较清晰了存储 IO 存在一定瓶颈但核心矛盾在于部分核心 SQL 因为统计信息问题选择了低效执行计划产生了大量无效 IO 和 CPU 运算。参数的调整空间不大重点应该放在 SQL 优化上。3. SQL 与参数双管齐下基于报告数据的调优实操拿到诊断结论之后接下来的工作就是动手调优。这个阶段我没有直接去改数据库参数而是先处理 SQL 层面的问题因为 SQL 的优化空间更大、见效更快而且风险相对于动参数要小得多。3.1 从执行计划入手处理 Top SQL针对报告里暴露的几条 Top SQL我逐一做了执行计划分析。其中一条 SQL 的问题比较典型它涉及两张表的关联查询从执行计划来看优化器选择了对其中一张大表做全表扫描尽管这张表本身是存在索引的。问题的根源在于这张表的统计信息长时间没有更新数据分布已经发生了较大变化但优化器还在用旧的数据来估算行数导致行数估算严重失真。对于统计信息问题最直接的解决方式是重新收集相关表的统计信息。在金仓 KingbaseES 里可以使用 ANALYZE 命令来完成这个操作。重新收集之后再次查看执行计划优化器已经能够正确识别到索引的存在并且选择了索引扫描的执行路径。这一步操作完成之后这条 SQL 的响应时间从原来的 2.1 秒下降到了 80 毫秒左右效果立竿见影。另外几条 SQL 也类似主要问题是关联条件上缺少合适的索引。对于这些 SQL我在确认了业务查询模式之后创建了匹配度较高的复合索引避免每次查询都走全表扫描。需要注意的是索引不是越多越好每增加一个索引都会增加写入操作的开销。所以创建索引之前一定要先确认查询模式确实需要并且评估写入频率是否能接受。3.2 参数调整的思路与边界SQL 层面优化完之后整体 CPU 使用率已经有了一定程度的下降但并没有完全达到预期。这时候我再结合报告中的内存和 IO 数据对几个关键参数做了微调。这里有一个原则数据库参数调整不要一次性改太多每次只改一两个参数改动之后观察一段时间确认稳定了再考虑下一个参数。我这次主要调整了两个方面。一是针对 IO 等待占比较高的情况适当增加了 work_mem 的取值让排序和哈希操作尽可能在内存中完成减少对临时文件的读写。但 work_mem 不是越大约好它是按操作分配的每个排序或哈希操作都可能申请这么大一块内存。并发高的时候过大的 work_mem 反而可能导致内存不足。所以这个参数要根据实际并发情况谨慎调整我当时只是从默认值往上调了一档并没有激进放大。二是调整了检查点相关的参数。从报告数据看检查点期间的 IO 波动比较明显频繁的检查点写入放大了存储压力。通过适当加大检查点间隔、提高检查点完成期间的写入速度上限可以让 IO 写入更平滑避免出现周期性抖动。调整后观察了一段时间IO 等待的峰值明显下降了。3.3 调优效果验证与观察参数调整和 SQL 优化完成后我重新使用 KSH 生成了新的性能报告和优化前的报告做了一次对比。核心指标包括CPU 使用率从高峰期的 90% 以上降到了 40% 到 60% 之间。平均响应时间从秒级回落到了几十毫秒级别。等待事件分布IO 相关等待占比明显降低CPU 等待占比也趋于健康。缓存命中率保持稳定在合理区间没有出现下降。这里有一个容易踩的坑是不要刚调完参数就急着下结论。数据库的运行状态受业务节奏影响很大某个时段的指标变好可能只是因为这个时段本身业务量小。保守一点的做法是至少观察一个完整的业务周期最好是高峰期和非高峰期都覆盖到再做最终的结论判断。我这次就是等了一个业务周之后确认各项指标都稳定在健康的范围内才算真正收尾。4. 排查与调优过程中的几个关键心得4.1 统计信息维护比调参数更重要这次排查让我对统计信息的重视程度又上了一个台阶。很多性能问题表面上看是 SQL 慢根子上其实是统计信息失真。数据库优化器判断执行计划非常依赖统计信息提供的行数估算。一旦统计信息不准确优化器就可能做出错误判断选一个低效的执行路径而我们还在傻乎乎地调参数、改 SQL结果怎么调都收效甚微。金仓 KingbaseES 的统计信息自动收集机制可以保证大部分情况下的统计信息是有效的但也不能完全依赖它。尤其是对于业务数据有明显周期波动的表比如每天都大量插入新数据、或者定期做批量删除的表统计信息很容易跟不上实际变化。我的建议是对这些关键表建立定期 ANALYZE 的维护任务同时也别忘了日常巡检时手动作一次检查。4.2 快照周期的设置对小周期业务很重要KSH 性能报告依赖快照点之间的数据变化如果快照周期太长很多短时间内的波动会被平均掉看不出真实的问题。如果快照周期太短又会生成大量无效数据分析效率反而降低。在实际使用中我会根据业务的实际情况来设计快照策略。如果业务的波峰波谷差异明显我会在高峰期前后各手工打一个快照做针对性分析。如果系统开启了自动快照功能我会确认快照间隔是否能覆盖到一个完整的高峰时段并且关注快照的保留策略避免需要回溯历史数据的时候发现快照已经被清掉了。4.3 结合业务场景解读报告数据不要迷信单一指标性能报告里的每一类数据都不是孤立存在的解读的时候一定要结合业务场景。比如等待事件里某类锁等待的占比较高如果仅仅看数值是比较吓人的但结合业务发现那是一个固定时间段的批量更新任务导致的属于预期内的行为就不能简单判定为异常。再比如某些 IO 等待高如果存储本身是机械盘那是硬件能力上限的问题调参数也解决不了根本问题需要考虑存储选型。做性能调优的人很容易陷入数字焦虑看到某个指标偏高就急着下手改配置。我在这个行业摸爬滚打这些年越来越体会到数据库调优更像中医问诊讲究望闻问切把各个维度的数据放到一起综合判断而不是头痛医头、脚痛医脚。4.4 记录完整的调优过程方便回溯这次调优过程中我养成了一个习惯每一步操作都做详细记录包括为什么改这个参数、改之前的值是多少、改之后的值是多少、观察结果如何。这些记录在调优完成后看似没什么用但后续如果系统再出现类似问题翻一下历史记录就能快速找到方向不用重新踩一遍坑。而且如果多个 DBA 共同维护一套环境清晰的操作记录也能避免大家各调各的互相之间缺乏沟通。5. 从一次调优延伸出的 KSH 使用建议5.1 把 KSH 性能报告纳入常态化巡检性能调优不是一锤子买卖而是一个持续的闭环过程。系统上线之后业务在发展数据在增长SQL 在变化硬件在老化任何一环的变化都可能带来新的性能问题。与其等问题爆发之后再仓促处理不如把性能报告做成常态化巡检的一部分。我建议的节奏是业务系统正式上线后先在高频业务时段生成一两份报告作为基线之后每两周或者每个月固定生成一份跟基线对比及时发现性能退化趋势。报告数据可以存档保留这样系统出现问题时还能结合历史数据回溯看看是什么时候开始变慢的什么操作导致的。5.2 报告多读几遍每一次都能发现新东西一份 KSH 性能报告生成之后我第一次看往往只能发现最明显的问题。等到调整完参数、优化完 SQL再回去翻同一份报告又能看到一些之前忽略的细节。这就是报告类工具的共性价值它的数据是相对全面的而我的注意力是有限的。所以不要指望只读一遍报告就能解决所有问题把报告留好每个阶段回头看都会有不同的收获。5.3 不同角色的使用者关注点完全不同最后想说一下KSH 性能报告不是 DBA 的专属工具开发人员和运维人员都能从中获得有价值的信息。DBA 关注的是实例健康度、参数配置、等待事件和存储表现开发人员更应该关注 Top SQL 统计找出代码里的潜在性能隐患比如缺少索引的关联查询、重复执行的低效语句等运维人员则可以重点关注资源使用趋势、IO 模式、慢查询增长情况为容量规划和硬件升级提供依据。一份报告的价值取决于看它的人带着什么问题去看。工具本身只是数据的搬运工真正的诊断能力还是来自对业务的理解、对数据库原理的把握以及在实战中积累的经验。写这篇内容也是希望大家在遇到 KingbaseES 性能问题时能少走一些弯路多一条靠谱的排查路径。
