SQLite 的「内存管理」在应用进程里主要体现为:页缓存(Pcache)解析与执行阶段的工作区临时排序/哈希结构 以及可选的 mmap 映射区。没有独立服务器进程替你做全局 buffer pool——每个连接、每个操作 都在你的进程地址空间里完成。调 cache_size 不是「给 SQLite 更多内存就更快」那么简单:还要问 连接数、临时表、大查询的排序落盘、容器 cgroup 限额

1 页面缓存(Pcache)机制直觉

  • 读页时先查 页缓存;未命中则读盘并放入缓存;
  • 缓存以 为粒度,与 page_size 对齐;
  • PRAGMA cache_size 控制当前连接可持有的缓存规模(注意正负单位区别:正为 KB 粗估、负为页数,具体以官方 pragma 页为准)。

池化误区:40 个连接各 cache_size=-2000,等价于 最多四十份热页,RSS 可能直线上升。

2 cache_size 调优步骤(可复现)

  1. 固定 workload(脚本回放同样的查询序列);
  2. 扫描 缺页率(若用 profiler)或 端到端延迟
  3. 逐步提高 cache_size,直到 边际收益趋近于零
  4. 容器内存上限 反推「允许的最大总缓存」。

嵌入式设备往往在 几十 MB 内权衡;服务器进程也要防止 与 JVM 堆叠罗汉

3 mmap_size:减少 syscall,不等于魔法

  • mmap 把文件片段映射进虚拟地址空间,大块顺序读可能受益;
  • 过大:虚拟内存占用、与 OS page cache 双重缓存 争议、32 位地址空间风险;
  • 建议:阶梯压测,观察 RSS、iowait、P99。

4 临时表与排序溢出

ORDER BYGROUP BYDISTINCT、复杂 JOIN 可能生成 临时 B-Tree;内存不够则 spill 到 temp 目录。症状:磁盘突击写入 + 延迟飙升

对策:

  • temp_store / temp_store_directory 配到快速本地 SSD;
  • 改写 SQL:减小中间结果集(过滤前移、索引覆盖);
  • 分批查询:keyset pagination 代替一次性排序全村。

5 内存溢出诊断清单

现象 可能原因
RSS 与连接数线性涨 每连接 cache 过大
查询中途磁盘抖 临时排序 spill
mmap 拉高 VSZ mmap_size 过大

工具:进程 RSS 曲线iostatsqlite3 编译时 SQLITE_TRACE(高级)、应用侧 慢查询日志

6 大数据集查询控制

  • 限定返回列,避免 SELECT * 拉动宽行;
  • LIMIT + 游标
  • 避免在应用层把 millions 行读到 List

7 与开源基准

  • cache_size、mmap_size 写入 版本化配置,Git diff 可见;
  • benchmark/ 目录固定 seed 与 DB 快照,CI 对比回归。

8 页缓存与 OS 页缓存的关系

SQLite 用户态缓存与操作系统 文件页缓存 可能 双重持有同一底层页:并非总是浪费——前者减少解析路径,后者减少磁盘往返;但若 mmap 过大且 cache 也大,可能出现 RSS 虚高。压测时同时记录 ps/topiostat,避免只看单一指标下结论。

9 嵌入式设备的特殊约束

无 swap 的小内存设备上,宁可减小连接池与 cache,也不要让 大排序 spillOOM killer 赛跑;temp_store_directory 指向 wear-leveling 友好的分区(某些 flash 场景)有时比调 cache 更能延寿。

总结

SQLite 内存调优 = 连接模型 × cache × 临时文件路径 × SQL 形状。先量 RSS 与延迟,再扭旋钮;否则容易变成「内存加倍,收益寥寥」。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐