SQLite 文件详解:结构、使用场景及关键限制

SQLite 文件是单个磁盘文件,保存了整个关系型数据库——包括表、索引和模式。SQLite 官方文档将其称为“主数据库文件”,并指出“SQLite 数据库的完整状态通常包含在其中”。在这句话中,“通常”这个词起到了关键作用。
如果你曾收到过 .db、.sqlite 或 .sqlite3 文件,并怀疑自己是否收到了完整的数据,那么这就是你需要深入了解的格式。
SQLite 文件究竟是什么
SQLite 自称为“一个进程内的库,它实现了一个自包含、无服务器、零配置、事务性的 SQL 数据库引擎”。该页面还指出,SQLite “没有独立的服务器进程”。应用程序只需链接该库并读取文件即可。
由此带来了两个结果。首先,数据库作为一个整体文件进行传输,这就是为什么如此多的应用程序都以这种方式分发数据。其次,该格式必须极其稳定,因为这些文件的寿命比编写它们的软件更长。SQLite 将“稳定、持久的文件格式”列为其核心特性之一。它还声明其代码属于公有领域,“可免费用于任何目的,无论是商业还是私人用途”。
这一规模很容易被低估。SQLite 官方的关于页面称,它“是世界上部署最广泛的数据库,其应用数量多到无法估量”。
文件内部有什么
100 字节的头部
前几个字节用于识别格式。在偏移量 0 处,文件包含一个 16 字节的头部字符串:SQLite format 3\000。无论文件扩展名是什么,工具都是通过该签名来识别文件的。
下一个字段比看起来更重要。在偏移量 16 处是一个 2 字节的整数,保存着“以字节为单位的数据库页大小”。文档指出,它“必须是 512 到 32768(含)之间的 2 的幂,或者是代表页大小为 65536 的值 1”。头部中的所有多字节字段都以高位字节在前的顺序存储。
紧接着在偏移量 18 和 19 处还有两个字节:文件格式的写入版本 and 读取版本。文档指出,该值为“1 表示传统模式;2 表示 WAL 模式”。
是“页”,而不是“行”
在头部下方,文件是一堆固定大小的页。规范中明确写道:“主数据库文件由一个或多个页组成。页的大小是 512 到 65536(含)之间的 2 的幂。同一数据库内的所有页大小相同。”
页从 1 开始编号,最大页数为 4,294,967,294。表和索引作为 B-tree 结构存在于这些页中,这就是为什么文本编辑器几乎无法显示任何有用内容的原因。
没人提及的伴生文件
这是最容易让人犯错的地方。文档提到完整状态“通常”在一个文件中,随后便指出了例外情况。在事务执行期间,SQLite “会将额外信息存储在名为‘回滚日志’(rollback journal)的第二个文件中”。在 WAL 模式下,这第二个文件则是预写日志(write-ahead log)。
因此,在应用程序正在写入时复制的文件,可能会丢失仍保存在伴生文件中的已提交数据。如果同事只给你发了一个 .db 文件,而数据看起来有些陈旧,这就是首先需要检查的地方。
如何打开 SQLite 文件
有三种途径,选择哪一种取决于你接下来的打算。
使用查看器读取。 桌面端和基于浏览器的 SQLite 查看器可以打开文件、列出表,并允许你点击浏览各行。这是了解“这里面到底有什么”最快的方法,通常对于初步查看已经足够了。
使用命令行或库进行查询。 sqlite3 命令行工具以及 Python、Node 和大多数其他语言中的标准库绑定可以直接读取该格式。当你已经了解模式并想要获取特定数据时,可以采用这种方法。
导出表并在其他地方进行分析。 将表导出为 CSV,然后导入到团队已有的任何工具中。这样做会丢失表与表之间的关系,而这恰恰是该格式所保护的核心内容。如果可能的话,请导出联接后的结果,而不是原始表。
为什么工具会提示该文件不是数据库
规范解释了这一点。每个有效的文件都以 16 字节的头部字符串 SQLite format 3\000 开头。如果读取器打开文件后在偏移量 0 处没有找到该签名,说明它接收到的不是 SQLite 数据库。
大多数情况可以归结为三个常见原因。一是文件传输不完整,虽然头部存在,但其余部分被截断了。二是文件被加密或被应用程序包装,导致前几个字节变成了其他内容。三是扩展名具有误导性,你实际收到的只是一个被热心人重命名了的普通导出文件。
SQLite 文件最大可以有多大
比这个问题通常暗示的要大得多。SQLite 的限制页面指出,数据库文件的最大大小为 4,294,967,294 页。在最大页大小为 65,536 字节时,数据库的最大大小约为 281 TB。
该页面对这一数字的坦诚令人耳目一新。它指出,这一上限“未经测试,因为开发人员无法获得能够达到该限制的硬件”。
行数也受到同样的限制。一张表中的理论最大行数是 2^64 行。文档指出,这一限制“是无法达到的,因为会先达到 281 TB 的最大数据库大小限制”。
对于实际工作来说,有用的启示恰恰与限制相反。如果有人递给你一个 .db 文件并警告说它很大,这种格式几乎绝对不会成为你的阻碍。创建文件时选择的页大小以及它是否包含索引,对实际体验的影响要远远大于任何文档中记载的上限。
你会在哪里遇到 SQLite 文件
- 应用程序导出。 桌面和移动应用经常将历史记录、设置和消息日志存储在你可以复制出来的 SQLite 文件中。
- 分析数据交接。 工程师会将快照作为一个文件发送,而不是授予数据库访问权限。
- 设备与遥测。 嵌入式系统由于没有可通信的服务器,因此会在本地进行写入。
- 归档。 该格式的长期稳定性使其成为必须保持多年可读的数据集的常见选择。
- 浏览器和工具内部。 许多本地工具都以这种方式保存状态,这就是为什么该扩展名会出现在技术支持工单中的原因。
WAL 和日志文件是用来做什么的
你可能复制过一个 .db 文件,并发现旁边放着一个 -wal 或 -journal 文件。这些就是规范中所描述的伴生文件,而删除它们正是人们丢失数据的原因。
回滚日志(rollback journal)是较旧的机制。在修改页之前,SQLite 会将该页的原始版本写入日志。如果写入中断,则可以恢复原始版本,这就是事务能够在崩溃中幸存的原因。
预写日志(write-ahead log)则颠倒了这一顺序。更改会先写入日志,稍后再更新主文件。头部会标记数据库处于哪种模式。偏移量 18 处的文件格式写入版本为“1 表示传统模式;2 表示 WAL 模式”。
实用规则直接源自关于完整状态的那句话。假设数据库处于 WAL 模式,而有人只给了你主文件。最近提交的更改可能仍然保存在你未收到的日志中。
So 当你拿到一个数据库文件时,请问两个问题:复制文件时应用程序是否正常关闭?是否有其他文件随附?这两个问题的答案通常都是“是”,而一旦不是,数据就会在不知不觉中与生产环境产生偏差。
SQLite 文件 vs CSV vs Parquet
| SQLite 文件 | CSV | Parquet | |
|---|---|---|---|
| 形态 | 多张表,一个文件 | 一张表,一个文件 | 一张表,一个文件或文件夹 |
| 类型 | 与数据一起存储 | 由读取器推断 | 与数据一起存储 |
| 关系 | 通过键和索引保留 | 丢失 | 丢失 |
| 人类可读 | 否 | 是 | 否 |
| 为查询而设计 | 是,使用 SQL | 否 | 是,由分析引擎查询 |
| 常见故障 | 缺少日志或 WAL 伴生文件 | 类型和分隔符猜测错误 | 工具链支持问题 |
如果你经常使用这些格式,我们关于 Parquet 文件 和 TSV 文件 的说明文章也对这两者进行了同样的介绍。
为什么团队会选择这种格式
无需运行任何服务。 因为 SQLite “没有独立的服务器进程”,所以交接工作只需复制文件,而不需要申请配置服务器。
类型在传输中得以保留。 日期列在接收端依然是日期。任何经历过 CSV 读取器将标识符误转为科学计数法的人,都能理解这一特性的价值。
关系也得以保留。 多个相关的表保存在同一个文件中,因此使数据具有意义的联接依然可用。
设计上保证了持久性。 SQLite 将“即使在断电后”也能保证事务完整性列为其核心特性之一,这就是为什么如此多的嵌入式软件都依赖它的原因。
值得了解的限制
一个文件,同一时间只能有一个写入者。 该引擎是嵌入式的,而不是以服务形式运行,因此其并发模型与客户端-服务器数据库不同。这是一种设计选择,而非缺陷,但它决定了该文件适合用于什么场景。
页大小在创建时即固定。 数据库中的每个页大小都相同,且该大小记录在头部中。你只需在创建时选择一次。
再次强调伴生文件规则。 任何仅抓取主文件的复制、备份或上传程序,都可能会遗漏日志或预写日志中的内容。
不透明性。 SQLite 文件无法像 CSV 那样直观地浏览。读取它需要专门的工具,而这恰恰是阻碍许多分析工作的摩擦点。
如何从 SQLite 文件中获取答案
传统的方法是安装客户端、打开文件、了解模式,然后开始编写 SQL。当你已经熟悉这些表时,这没问题。但如果你今天早上刚拿到文件,而会议今天下午就要召开,这种方法就太慢了。
更快捷的途径是直接提问。Powerdrill Bloom 允许你使用自然语言处理数据,并返回附带来源的答案。其主页承诺“每一个数字都会附带其背后的页、行和具体数据”。在此基础上,同一个工作区还可以生成图表、表格或简短的幻灯片。
如果这是你的常规工作流,有两个相关页面值得了解。Chat with Database 介绍了通过对话方式获取结构化数据的途径,而 Text to SQL 则适用于你想要获取查询语句本身的情况。如果你的交接数据是扁平的导出文件,CSV AI assistant 页面则涵盖了这一路径。
头部还能告诉你的一件事
由于页大小保存在固定的偏移量处,因此在正式打开文件之前,你就可以了解到一些有用的信息。使用 4,096 字节页大小创建的数据库与使用 65,536 字节页大小创建的数据库行为不同。这一选择在文件创建时就已经确定,且仅能选择一次。
这不是一个你以后可以随便更改的数字。它属于模式决策的范畴,而不是一个简单的设置。
结论
SQLite 文件是封装在单个文件中的完整数据库。它包含一个 16 字节的签名、记录在偏移量 16 处的页大小,以及一堆承载表和索引的固定大小的页。它便于传输、保留了数据类型,并且能保持多年可读。
请记住规范中特别提醒的一个注意事项:完整状态“通常”在该文件中。在事务执行期间,其一部分内容会保存在旁边的回滚日志或预写日志中。在信任该副本之前,请先检查是否存在伴生文件。
当你拿到文件并需要获取答案而不是研究模式时,请尝试 Powerdrill Bloom 并直接针对数据提出你的问题。
常见问题解答
.db、.sqlite 和 .sqlite3 之间有什么区别?
结构上没有区别。这三者都是同一格式的常规扩展名,真正的标识符是文件开头的 16 字节头部字符串 SQLite format 3\000。
我该如何知道 SQLite 文件使用的是什么页大小?
它记录在头部中。偏移量 16 处的 2 字节整数保存着以字节为单位的页大小。它必须是 512 到 32768 之间的 2 的幂,或者是代表 65536 的值 1。
SQLite 文件是完整的数据库吗?
通常是,但并非总是如此。文档指出,在事务执行期间,SQLite 会在回滚日志中保存额外信息。在 WAL 模式下,这些信息则会写入预写日志中。
我可以直接在 Excel 中打开 SQLite 文件吗?
不能直接打开,因为该文件存储的是 B-tree 页,而不是文本行。常见的方法是先将表导出为 CSV,或者使用能够读取该数据库格式并返回结果的工具。
SQLite 可以免费用于商业用途吗?
是的。SQLite 声明其代码属于公有领域,“可免费用于任何目的,无论是商业还是私人用途”。