在 SQLite 中优先使用 STRICT 表

查看原文 HN 讨论

文章摘要

SQLite 从 3.37.0 版本(2021 年 11 月)起引入了 STRICT 表——只要在建表语句末尾加上 STRICT 关键字(如 CREATE TABLE people (name TEXT) STRICT;),SQLite 就会对列类型做严格检查。作者强烈建议默认使用这一特性,因为它能在早期拦截一整类数据完整性问题。

作者指出普通(非 STRICT)表存在几个”反直觉”的行为:其一,向 INTEGER 列插入文本不会报错;其二,你可以给列声明根本不存在的类型(如 DATETIME、UUID、JSON,甚至写错成 BLOBB),SQLite 照单全收,从而把拼写错误或误解悄悄埋进 schema;其三,你甚至可以完全不写类型。更糟的是,SQLite 的类型转换是”尽力而为”:字符串 '10' 会被转成整数 10,但无法转换的值(如 '1O')则原样存入整数列,导致同一列里混着不同类型的值。

STRICT 表的优点是:无损转换依然有效('123' 仍会存为整数 123);提供了 ANY 类型以便在确实需要灵活性时使用;作者实测没有观察到明显的性能损耗。其局限在于:无法通过 ALTER 把已有的非 STRICT 表原地转换为 STRICT,必须重建表(若已有非法数据会有丢失风险);不兼容 3.37.0 之前的版本;而且 SQLite 官方明确”不同意”这一偏好,认为灵活类型在键值存储、导入脏数据等场景中有其合理用途。

HN 评论精华

评论区的主流观点是希望 STRICT 成为默认,同时也有人细致地解释了 SQLite 为何不这么做。