当前位置: 首页 > news >正文

SQLite / LiteDB 单文件数据库为何“清空表后仍占几 GB”?——原理解析与空间回收实战

关键词: SQLite、LiteDB、VACUUM、WAL、auto_vacuum、文件瘦身、数据库维护

在嵌入式或桌面、IoT 网关等场景,很多同学都会选择单文件数据库(SQLite、LiteDB、SQL CE…)。
最近群里一位朋友反馈:

“我的 test.db 已经把业务数据全删光,但文件依旧 3.8 GB!
甚至重启程序也没变小,这是为啥?”

别急,这并不是磁盘“被占用不释放”,而是单文件数据库按页管理延迟回收的正常机制。本文将:

  • 揭秘删除数据后文件仍超大的五大原因
  • 手把手演示在 Linux / Windows 下 VACUUM / Rebuild 压缩操作
  • 给出线上环境自动瘦身写放大平衡的最佳实践

1 原理:删除 ≠ 收缩,空闲页仍在文件里

以 SQLite 为例:

  1. 固定页 (Page) 结构 – 默认 4 KiB。
  2. DELETE / DROP TABLE 时,记录被打上 unused flag,所在页被挂到 freelist
  3. 文件尾部不会立即截断,因此操作系统看到的文件大小不变。
  4. WAL 模式 下,.db-wal 日志同样采用追加写,旧数据也留在磁盘。
  5. 只有执行 VACUUM (或 auto_vacuum=FULL 时的新页写满)才会真正搬运存活数据 → 重写文件 → 释放未用 page。

LiteDB(.NET 生态)等其他单文件 DB 也采用相似策略,名字不同(如 Rebuild())而已。


2 五大常见原因对照表

#文件仍巨大的原因是否“异常”解决手段
1空闲页积累:大量删除后未 VACUUM⚠️ 正常VACUUM;
2WAL 日志残留.db-wal + .db-shm 未 checkpoint⚠️ 正常PRAGMA wal_checkpoint(TRUNCATE);VACUUM;
3预扩容:曾设置 max_page_count、或工具一次写满✅ 设计如此取消限制 → VACUUM;
4隐藏/历史表:程序保留备份、软删除表取决于需求删除对象 → VACUUM;
5非 SQLite:LiteDB、ESENT、LevelDB 等⚠️ 正常对应的 Shrink/Compact API

3 手动压缩:三步到位

?? 注意VACUUM 会生成 同大小临时文件,磁盘需有足够空间并加排他锁,务必在维护时间执行!

# 进入 sqlite3 shell
sqlite3 test.db-- 1) 看看是否在 WAL 模式
PRAGMA journal_mode;-- 2) 手动触发 checkpoint(若是 WAL)
PRAGMA wal_checkpoint(TRUNCATE);-- 3) 查看空闲页统计
PRAGMA freelist_count;-- 4) 真正压缩
VACUUM;.quit

若使用 LiteDB(C#):

using (var db = new LiteDatabase("test.db"))
{db.Rebuild(); // 等价于 VACUUM
}

压缩后,你会发现文件大小立刻降到 “活跃数据 + 索引” 所需空间。


4 线上环境的最佳实践

  1. 启用 WAL

    PRAGMA journal_mode=WAL;
    

    并定时

    PRAGMA wal_checkpoint(TRUNCATE);
    
  2. 开启 incremental_vacuum + 定期触发

    PRAGMA auto_vacuum=INCREMENTAL;
    PRAGMA incremental_vacuum;      -- 可以指定页数
    

    这样每晚只回收 N 页,避免一次性 I/O 峰值。

  3. 写扩散 vs. 瘦身平衡

    • 全量 VACUUM:文件最小、查询碎片最少,但重写成本高。
    • auto_vacuum=INCREMENTAL:每日轻量回收,I/O 峰值低。
      结合业务 QPS、磁盘 IOPS 选择折中方案。
  4. 监控 freelist_count + 文件大小
    通过 PRAGMA freelist_count; 与 Node 导出指标,当空闲页阈值 > 30 % 时触发压缩任务。


5 FAQ

问题解答
VACUUM 会锁表吗?会对整个 DB 加 排他锁,期间所有读写被阻塞。WAL 模式也不例外。
磁盘不足怎么压缩?可先复制到大磁盘、《或》用 VACUUM INTO 'new.db'; 再替换。
WAL 文件多大合理?官方建议 < 1 GiB;通过 PRAGMA wal_checkpoint(TRUNCATE) 清空到 ~0 字节。
能否自动释放?设置 auto_vacuum=FULL,但写放大会增 I/O;线上更常用 INCREMENTAL

结语

“删光数据文件却不变小” 99 % 都是因为你没有 VACUUM / Rebuild
了解单文件数据库的页式存储后,你就能自信地将文件瘦到最精简,也避免下次被 3 GB 大文件吓到。

http://www.dtcms.com/a/285510.html

相关文章:

  • 基于单片机智能浇花控制系统设计
  • 短视频矩阵系统:选择与开发的全面指南
  • Instagram千号矩阵:亚矩阵云手机破解设备指纹检测的终极方案
  • Hadoop与云原生集成:弹性扩缩容与OSS存储分离架构深度解析
  • ThreadLocal 在 Spring 与数据库交互中的应用笔记
  • 车载监控录像系统:智能安全驾驶的守护者
  • SGLang 推理框架核心组件解析:请求、内存与缓存的协同工作
  • Android音视频探索之旅 | Webrtc 1对1音视频通话核心流程分析
  • Go语言实战案例-斐波那契数列生成器
  • 分表聚合助手类
  • UniApp TabBar 用户头像方案:绕过原生限制的实践
  • 依托CCLinkIE转ModbusTCP网关的转换达成西门子PLC连接配置案例
  • 涉及海量数据的查询SQL建议使用“数据库函数”封装并调用
  • Rust实战:高效对接Postman API
  • 【Nginx】nginx+lua+redis实现限流
  • 【Lua】闭包可能会导致的变量问题
  • 去中心化交易所(DEX)深度解析:解码行业头部项目
  • 双向广搜算法详解
  • 【现有资料整理】灵枢 - 用于医学领域的 SOTA 多模态大语言模型
  • 对Yii2中开启`authenticator`后出现的跨域问题-修复
  • .QOI: Lossless Image Compression in O(n) Time
  • 变量命名规则
  • git--gitlab
  • 性能远超Spring Cloud Gateway!Apache ShenYu如何重新定义API网关!
  • 无标记点动捕:如何突破传统娱乐边界,打造沉浸式交互体验
  • 高速公路自动化安全监测主要内容
  • Elasticsearch+Logstash+Filebeat+Kibana部署(单机部署)
  • 在 Jenkins 中使用 SSH 部署密钥
  • JAVA高级第五章,简易超市会员管理系统
  • sqli-labs靶场通关笔记:第29-31关 HTTP参数污染