SQLite 应该有(Rust 风格的)edition
SQLite 长期坚持向后兼容,如今正与人们对更安全默认值的现代期待发生冲突,因此有人呼吁引入类似 Rust 的 “edition” 机制,让新数据库在不破坏旧数据库的前提下采用更严格的行为。评论者讨论了单个 `PRAGMA edition=2026` 式开关是否能真正提升可靠性,还是会因为 SQLite 作为可移植磁盘格式的角色而模糊掉重要的配置权衡,比如强制外键、严格类型、busy timeout 和 WAL 模式。另一些人则认为,包装库、编译期标志,甚至其他嵌入式数据库(如 DuckDB 或 Firebird)可能更适合获取更强保证,同时保留 SQLite 的极简性和小体积。
Edition 概念与目标
- 许多评论者喜欢“edition”或“compatibility level” pragma 的想法,它把一组现代默认值(例如更严格的类型、外键强制、busy timeout、WAL)打包在一起,同时不破坏旧代码。
- Edition 被视为一种可选启用的方式,帮助摆脱 20 年前的默认设置,同时保留 SQLite 的向后兼容承诺。
- 讨论中还类比了 Rust editions、C++ 的 “epochs/profiles”、CMake policies、Postfix
compatibility_level以及 JS 的use strict。
向后兼容性与可移植性
- SQLite 是一种数据容器,经常在机器和工具之间迁移;较旧的
/usr/bin/sqlite3二进制文件常常会读取由更新的嵌入式版本创建的文件。 - 质疑者担心 editions 可能会:
- 需要同时理解底层 pragma 和 edition 映射。
- 如果 edition N 暗含后来才加入的特性,就会把中间版本的 SQLite 排除在外。
- 在启用更严格语义时,使现有数据的处理更复杂。
- 支持者回应说,这些问题在今天使用单个 pragma 时基本也同样存在,并提出:
- 将 editions 纯粹做成连接级宏(不存入文件)。
- 保持严格的单向规则和自描述元数据。
默认值:外键、类型、busy timeout、WAL
- 许多人同意当前默认值(不强制外键、宽松类型、无 busy timeout、rollback journal)对典型的“应用数据库”用途来说很差,通常都会被覆盖。
- 也有人为现状辩护:
- 嵌入式/低资源环境可能更偏好极简和宽松类型。
busy_timeout本质上取决于应用;选择 5 秒、1 秒还是 60 秒都很随意。- WAL 是不同的格式,并非普遍支持,而且被认为在损坏风险上更高。
类型、STRICT 表与数据质量
- 一些评论者认为 SQLite 的类型系统“危险”,并希望默认就是严格类型。
- 另一些人则认为,宽松类型对于导入脏乱的 CSV/遗留数据非常有价值,因为无效日期、数字等情况很常见。
- STRICT 表被视为有用的一步,但并不是完整的校验方案;严肃的校验往往仍然应放在更高一层。
SQLite 的范围与替代方案
- 有人强烈反对把 SQLite 变成完整的客户端-服务器、高并发系统;如果你需要这些功能,有些人会说“用 Postgres”,或者改用其他嵌入式引擎(DuckDB、Firebird)。
- 反方观点:即使是本地应用数据库,也应该有更安全的默认值;editions 或功能集可以在不改变遗留行为的前提下提供这些能力。
实现与生态系统担忧
- 担忧包括:每增加一个 edition 都会带来代码膨胀、测试面扩大,以及潜在的混淆(“edition 2026”掩盖了实际启用的内容)。
- 建议的缓解办法:把 editions 实现为现有 pragmas 上的很小一层宏;也可以只允许有限数量的版本,或用功能集而不是按年份命名的 editions。
- 一些 ORM 和包装器生态对较新的 SQLite 特性(例如 STRICT)支持滞后,这会在工具链跟上之前降低实际收益。