本节摘要:内存是数据库性能第一利器——数据在内存不用读盘。本节讲清楚缓冲池、查询缓存、排序区、连接缓冲等内存参数调优,让数据库尽量在内存操作。

数据库性能瓶颈通常是 IO(磁盘慢)。内存缓存数据避免读盘——内存访问纳秒级,磁盘毫秒级,差 10 万倍。
内存参数调优目标:
前提:内存够大。内存不够则参数再大也用不上(或 swap 更慢)。
innodb_buffer_pool_size——InnoDB 最重要的参数。
作用:缓存数据页和索引页。数据在缓冲池则内存访问,否则读盘。
调优:
其他 InnoDB 内存参数:
shared_buffers——PG 最重要的参数。
作用:共享缓冲池缓存数据页。
调优:
work_mem:排序/聚合内存区。
maintenance_work_mem:维护操作(VACUUM/CREATE INDEX)内存。
effective_cache_size:告诉优化器 OS 缓存大小,影响执行计划选择。
query_cache_size——MySQL 查询缓存。
注意:MySQL 8.0 已移除查询缓存,因:
8.0 前:读多写少且结果稳定可用,但通常弊大于利。替代:应用层缓存(Redis)。
MySQL:
PostgreSQL:
原则:排序/聚合缓冲调大到不落盘即可,不是越大越好(每连接/每操作分配,总内存爆炸)。
1. 看内存使用
2. 调缓冲池
3. 调排序/临时
4. 算总内存
5. 监控 swap
⚠️ 常见误读:以为"缓冲越大越好"。缓冲池受物理内存限制,且要留 OS 和其他。排序缓冲每连接每操作分配,过大 × 连接数 OOM。要算总内存。
💡 关键直觉:内存最重要——内存访问纳秒 vs 磁盘毫秒差 10 万倍。InnoDB buffer_pool_size(专用 DB 70-80% 物理内存,多实例减锁,预热,命中率 >99%)、log_buffer(大事务调大)。PG shared_buffers(25% 物理内存,PG 还用 OS 缓存)、work_mem(排序/聚合每查询每操作,默认 4MB 调 16-64MB,总=work_mem×连接×操作算 OOM)、maintenance_work_mem(VACUUM/建索引 1-2GB)、effective_cache_size(优化器参考不分配)。MySQL 查询缓存 8.0 移除(失效开销大/锁竞争/命中率低,用 Redis 替代)。排序/连接缓冲(sort_buffer/join_buffer/tmp_table_size 调大避免落盘,每连接分配算总内存)。流程:看内存使用→调缓冲池(命中率 <99% 加大)→调排序/临时(监控 filesort/Using temporary)→算总内存→监控 swap 接近 0。
内存参数不是孤立的旋钮,而是一份预算的分配方案,调优前先建立全局观。一台数据库服务器的内存切成几块:操作系统与文件系统缓存(要留,别全给数据库)、数据库进程自身(代码与连接内存,随连接数增长)、缓冲池(最大头,数据页的居住地)、各类工作区(排序、哈希、连接的临时空间)。分配的次序原则:先保操作系统的底线(通常几个点到一成),再按"独享工作区乘以最大并发"预留工作区上限,剩余的大头给缓冲池——颠倒了次序(先设大缓冲池再算工作区)就会出现高并发时内存不足、临时落盘的隐性劣化。调整的观察指标:缓冲池命中率与脏页比例(缓冲池是否够)、临时表落盘次数(工作区是否够)、交换区活动(总预算是否超了物理内存——一旦开始换页,所有优化清零)。内存调优的终点状态是三条曲线的稳态:命中率高位平稳、脏页在刷写能力内、零换页。达到这个状态后,继续加内存的边际收益递减——钱该花去第 6 章的层了。
内存章的收官给缓冲池命中率的深度分析方法——这个指标看似简单(命中率九成九很好),其实分层才有信息量。层一,全局命中率的陷阱:全局九成九的命中率下可能藏着一类查询命中率只有七成(热表近百分百拉高了平均)——全局指标是遮羞布,按表或按页类型分解才见真相。层二,命中与年龄的关系:新加载的页天然未命中,批量任务(报表、导出)会短暂拉低命中率——把命中率按时间切片与任务对齐,区分"结构性的缓存不足"与"任务性的正常抖动"。层三,工作集的变迁:业务形态变化(新模块上线、数据量增长)让热数据慢慢超过缓冲池容量,命中率以每月零点几个百分点的速度阴跌——这种慢性病用月度趋势图才能看见,日视图里它就是噪音。三层分析做完,"要不要加内存"就不再是感觉题:结构性不足(分解后仍低且与任务无关、趋势阴跌)加内存立竿见影;任务性抖动加内存是浪费,限流任务或错峰才是解。指标分析的功力,全在这种"从单一数字到分层证据"的展开里。
内存章给一个压测校准的操作模板,让参数设置摆脱文档抄作业。第一步,负载画像:用生产流量录制或回放工具,准备能代表峰值形态的压测脚本(读写比、数据访问分布要与真实接近——随机均匀的压测会得出误导性的缓存结论)。第二步,阶梯实验:缓冲池从小到大取五档,每档跑同负载,记录命中率、时延、IO 量——画出"命中率与缓冲池大小"的关系曲线,找到拐点。第三步,定点验证:拐点后的下一档做七十二小时长稳(防慢性泄漏与碎片化侵蚀),确认稳定。第四步,登记入册:参数值、曲线图、实验条件写入参数台账,下次升级数据库版本时重跑。这套方法每次一个周末的工作量,换来的不是"最优参数"(它不存在)而是"有据可依的参数"——台账里的曲线比任何论坛帖子的推荐值都更属于你的系统。参数调优的成熟标志,就是团队讨论参数时引用自己的实验曲线,而不是别人的博客。
问:缓冲池到底设多大,有没有一步到位的公式? 答:物理内存减系统预留减连接工作区上限后全给缓冲池——但"一步到位"的心态要不得:先按公式起步,跑两周命中率曲线,再按拐点微调;内存参数是"先算后测再定"的三段式,不是一锤子买卖。问:加内存后命中率没升反降,怎么回事? 答:三个常见原因——工作集被新业务扩大(加的量被新流量吃掉,看分表命中率定位)、批量任务污染缓冲(新内存让大扫描跑得更欢、冲掉的页更多,给批量限流或独立实例)、统计口径变化(监控的重启计数器没清零)。内存问题的排查口诀:先看分解(哪类命中率降)、再看时间线(与什么变更对齐)、最后看任务(谁在污染)——顺序对了,怪事不怪。
补最后一个细节:内存参数变更后的观察期里,除了命中率与等待,还要看"数据库启动后的预热时长"——重启后缓存从冷到热的爬坡时间会随缓冲池变大而拉长(几十GB的池预热可能以小时计),主从切换频繁的系统要为预热期留缓冲(比如提高预热优先级或错峰切换),这是大内存配置的隐性代价,账要算全。
补一个容量弹性场景的提醒:云上或资源池化的环境里,内存参数要为"弹性伸缩"预留设计——动态调整内存的数据库(部分新版本支持在线调缓冲池)在缩容时的脏页回刷要时间,缩容操作的编排要留这个窗口;固定内存的环境里,超卖(多实例内存配额之和超过物理内存)是常见的隐性雷区,部署表上永远要有一列"物理机内存与已分配总和"的对账——内存这个资源,超卖的那一刻就已经开始收费(以换页的形式)。