SQLite的数据类型有哪些?如何根据存储场景正确选择?

来源:网站建设教程作者:广州网站建设头衔:草根站长
导读:本期聚焦于广州网站建设创作的《SQLite的数据类型有哪些?如何根据存储场景正确选择?》,敬请观看详情。SQLite的数据类型体系和MySQL、PostgreSQL等传统数据库有本质区别,它采用动态类型机制,核心是五种存储类:NULL、INTEGER、REAL、TEXT和BLOB。建表时虽然可以声明INT、VARCHAR等类型,但实际存储由类型亲和性规则决定,同一个字段甚至可以存入不同类型的数据。本文将详细梳理SQLite的存储类、INTEGER主键与ROWID的关系、TEXT编码方式、BLOB的使用场景,并深入解析类型亲和性判定规则和typeof函数的用法,结合用户信息表、日志表、二进制文件存储等实际场景,分析类型选择对存储空间和查询性能的影响,帮助你避开隐式转换带来的查询陷阱。

SQLite的数据类型设计在关系型数据库中非常独特。它不像MySQL那样严格校验列类型,而是采用动态类型加类型亲和性的机制。也就是说,你在建表语句里写的类型并不是强约束,真正决定数据在磁盘上如何存储的是存储类(Storage Class)。理解这套机制,是用好SQLite的第一步,也是避免出现"查不出数据"这类诡异问题的前提。

SQLite的数据类型有哪些?如何根据存储场景正确选择?

一、SQLite的五种存储类

SQLite内部只有五种存储类,任何值在存储时都必然属于其中一类。第一种是NULL,表示空值,不占用实际数据空间。第二种是INTEGER,带符号整数,根据数值大小动态使用1、2、3、4、6或8个字节存储,这是SQLite节省空间的典型设计——存一个100以内的数字只占1字节,而不是固定8字节。

第三种是REAL,8字节的IEEE浮点数。第四种是TEXT,字符串,默认以UTF-8编码,也可以在建库时指定UTF-16le或UTF-16be。第五种是BLOB,二进制大对象,数据按输入时的原始字节存储,不做任何转换。可以用内置函数typeof()查看某个值实际所属的存储类:

-- 查看不同值的存储类
SELECT typeof(100);        -- 返回 integer
SELECT typeof(100.0);      -- 返回 real
SELECT typeof('100');      -- 返回 text
SELECT typeof(x'414243');  -- 返回 blob
SELECT typeof(NULL);       -- 返回 null

需要注意的是,INTEGERREAL是严格区分的。100100.0在SQLite里是两个不同存储类的值,虽然比较时会认为相等,但排序和索引行为可能有细微差别。

二、类型亲和性:声明类型如何影响实际存储

既然实际存储由存储类决定,那建表时的类型声明有什么用?答案是类型亲和性(Type Affinity)。每张表的每一列都有一个亲和性,它决定了数据插入时倾向被转换成哪种存储类。比如某列的亲和性是INTEGER,你插入字符串"123",SQLite会尝试把它转成整数123再存。

亲和性的判定基于声明类型的字符串匹配,规则按优先级依次是:如果声明类型包含"INT",亲和性为INTEGER;包含"CHAR"、"CLOB"或"TEXT",亲和性为TEXT;包含"BLOB"或类型为空,亲和性为BLOB(也叫NONE);包含"REAL"、"FLOA"或"DOUB",亲和性为REAL;其余情况(如包含"DATE"、"BOOL"等)默认为NUMERIC。看下面的例子:

CREATE TABLE demo (
    a INT,        -- INTEGER亲和性
    b VARCHAR(20),-- TEXT亲和性
    c BLOB,       -- BLOB亲和性,存什么就是什么
    d DATE,       -- NUMERIC亲和性
    e BOOLEAN     -- NUMERIC亲和性
);

-- c列存入字符串,会原样保留为text
INSERT INTO demo VALUES ('12', '34', '56', '2024-01-01', 'true');

SELECT typeof(a), typeof(b), typeof(c), typeof(d), typeof(e) FROM demo;
-- 结果: integer | text | text | text | text
-- 注意a被转换成了整数,d和e的字符串无法无损转数字,保持text

SQLite没有内置的BOOLEAN和DATE类型。TRUEFALSE关键字只是整数1和0的别名,日期时间通常以TEXT(ISO8601字符串)、REAL(儒略日)或INTEGER(Unix时间戳)三种方式存储,配合date()strftime()等函数处理。

三、INTEGER主键与ROWID的优化机制

几乎所有SQLite表都有一个隐藏的64位整数行标识ROWID。如果某列声明为INTEGER PRIMARY KEY,该列就成为ROWID的别名,这是SQLite中唯一接近"强类型"的情况——这一列只能存整数,且插入NULL时会自动取未使用的最大值加一,实现自增效果,不需要写AUTOINCREMENT关键字。

CREATE TABLE users (
    id INTEGER PRIMARY KEY,  -- 即ROWID别名,自动自增
    name TEXT NOT NULL,
    age INTEGER
);

INSERT INTO users (name, age) VALUES ('张三', 28);
SELECT rowid, id FROM users;  -- 两列值相同

这个设计的性能意义重大:INTEGER PRIMARY KEY上的查找直接定位B树记录,是最快的访问路径。而表如果设置了WITHOUT ROWID选项,则没有隐藏行号,数据按主键组织,适合主键较长且几乎总是按主键查询的场景,能节省一整棵索引树的空间。

四、不同存储场景下的类型选择建议

存储普通业务数据时,遵循"声明类型贴近亲和性规则"的原则即可。用户名、邮箱、地址这类字符串用TEXT;数量、状态码、年龄用INTEGER;金额要特别注意——REAL存在浮点精度问题,0.1 + 0.2不等于0.3,涉及金钱计算建议以"分"为单位存INTEGER,或存TEXT后用程序层的高精度类型解析。

存储时间戳时,推荐用INTEGER存Unix时间戳,占4或8字节且比较排序快;如果需要人类可读且直接使用日期函数,用TEXT存ISO8601格式如"2024-01-01 12:30:00"。两者的索引范围查询都很高效,混合使用则是大忌,同一列里既有字符串日期又有整数时间戳,会让查询条件无法命中索引。

存储图片、加密数据、序列化对象等二进制内容用BLOB。BLOB不做编码转换,读写原样进原样出,适合存缩略图、证书、protobuf数据。但要注意单条BLOB不宜过大,默认建议控制在百万字节以内,超大文件更适合存文件系统路径,数据库里只存引用。

五、常见陷阱与排查方法

最经典的坑是隐式转换导致查询失配。假如某列是TEXT亲和性,你用整数条件去查,索引可能失效或结果不符合预期。排查时优先使用typeof()确认数据实际存储类,用EXPLAIN QUERY PLAN看是否走了全表扫描。另外,拼接SQL时传参类型要和列亲和性匹配,建议始终使用参数绑定而不是字符串拼接,让驱动层正确处理类型转换。

总结来说,SQLite的类型系统看似宽松,实则有一套清晰的规则。记住五存储类、理解亲和性判定、善用INTEGER主键优化、按场景匹配TEXT与INTEGER的时间存储方式,就能既享受SQLite轻量灵活的优势,又避开动态类型埋下的坑。

SQLite数据类型存储类类型亲和性修改时间:2026-09-01 04:22:30

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。