首页 / SQLite 入门教程 / PRAGMA

SQLite 入门教程

PRAGMA

本教程共 50 篇 · 第 41 篇 · 更新于 2026-07-31

sqlitepragmaforeign_keys元信息

41. PRAGMA

本节目标:学完本章你能用 PRAGMA 读取数据库元信息(表结构、索引、编码等)并调整运行时行为(外键开关、缓存大小、同步模式等)。

PRAGMA 是 SQLite 特有的”特殊命令”,用来读取或设置数据库的各种环境变量与状态标志。它既不是标准 SQL 的表,也不是普通函数,而是 SQLite 留给你的”控制面板”。回想 SQLite 的出身:serverless、零配置,整个数据库就是单个文件,没有常驻服务进程帮你管状态。所以很多”该不该开外键""缓存多大""怎么同步落盘”这类开关,就通过 PRAGMA 在连接层面直接设定。

PRAGMA 有两种用法:只写名字是”读”,写 名字 = 值 是”写”。

PRAGMA foreign_keys;        -- 读当前外键开关
PRAGMA foreign_keys = ON;   -- 打开外键强制

常见坑(外键默认关闭)

SQLite 默认不强制外键约束! 即使你建表时写了 REFERENCES,只要没显式打开,插入违反参照完整性的数据也不会报错。而且 PRAGMA foreign_keys = ON连接级别的设置,不是写进数据库文件的——每一次新连接(包括每次重新打开 CLI)都得重新执行,它不会”记住”。这是新手最常踩的坑:在 A 连接开了外键、在 B 连接插入脏数据,结果 B 完全没拦。官方在 foreignkeys 文档里也明确要求由应用每次连接时设置。

一、最常用的几个 PRAGMA

foreign_keys:外键强制开关,上文已强调。涉及 orders.user_id 引用 users.id 这类关联时务必先开。

cache_size:设置内存页缓存的页数(默认 2000 页,最小 10 页)。注意它是”临时”的,只对当前连接有效,且是按页算不是按字节。

PRAGMA cache_size = 10000;

journal_mode:事务日志模式,影响并发与崩溃安全。常用值:DELETE(默认,事务结束删日志)、WAL(预写日志,读写并发更好)。WAL 模式在嵌入式/高读场景很受欢迎。

PRAGMA journal_mode = WAL;

synchronous:控制数据写入物理存储的激进程度。OFF(0) 不同步、NORMAL(1) 关键序列后同步、FULL(2) 每次关键操作都同步。FULL 最安全但最慢,OFF 最快但掉电可能损坏。

encoding:数据库字符串编码(UTF-8 / UTF-16le / UTF-16be),通常在建库时定好。

user_version / schema_version:存在数据库头里的 32 位整数。user_version 完全由开发者自由使用(比如做”数据库 schema 版本号”),schema_version 由 SQLite 在每次改结构时自增,一般别手动改。

二、读取元信息的 PRAGMA

PRAGMA 也是”查看数据库内部结构”的好工具,比翻 sqlite_master 更省事:

PRAGMA作用
table_info(表名)查看某表的列:序号、列名、类型、可否为 NULL、默认值、是否主键
index_list(表名)列出与表相关的所有索引
index_info(索引名)查看某索引包含哪些列
foreign_key_list(表名)查看表上的外键定义
database_list列出当前所有已打开/附加的数据库
page_count / page_size当前页数 / 页大小(乘积约为文件字节数)
freelist_count当前被标记为空闲可复用的页数
PRAGMA table_info(users);
PRAGMA index_list(orders);

举个完整例子:假设 orders(user_id) 引用了 users(id),想确认这张表到底挂了哪些外键,用 foreign_key_list

PRAGMA foreign_key_list(orders);
-- 返回:id, seq, table(被引用表), from(本表列), to(被引用列), on_update, on_delete, match

database_list 在多库/附加(ATTACH)场景下尤其有用,能一次看清当前连接里挂了哪几个库、分别指向什么文件——对 SQLite 这种”单文件即数据库、可同时 ATTACH 多个文件”的模型来说,是理清连接拓扑的利器。

重点提示

journal_mode = WAL 是实践中最常被推荐的优化之一。DELETE 模式下写操作会阻塞读;WAL(Write-Ahead Logging)模式下,读和写可以真正并发,读写性能都更好,特别适合”读多写少”的嵌入式/单机应用。代价是会产生 -wal-shm 两个附属文件,备份时要一并带上或先 PRAGMA wal_checkpoint

重点提示

许多只读、无副作用的 PRAGMA(如 table_infoindex_list)还能当成”表值函数”来用,也就是可以出现在 SELECT ... FROM pragma_table_info('users') 里,方便和其他表 JOIN 或过滤。这个特性从 3.16.0 起支持。带副作用或要传参设置的 PRAGMA 则不能这么用。

三、其他值得了解的设置

auto_vacuum:控制删除数据后数据库文件是否自动收缩(0 关闭 / 1 全自收缩 / 2 增量,需手动 incremental_vacuum)。默认关闭,文件不会自动变小,需用 VACUUM 命令整理(详见维护章)。

recursive_triggers:是否允许触发器连锁触发另一个触发器,默认关闭。

case_sensitive_like:控制 LIKE 是否区分大小写,默认不区分。

temp_store:临时表/临时数据放文件还是内存(0 默认 / 1 文件 / 2 内存)。在内存充裕、追求临时排序/分组速度的场景可设成 2,但要注意内存总量,别让大查询把内存吃满。

实用技巧

排查”为什么这张表查得慢”时,一个实用组合是:PRAGMA table_info(表名) 看字段、PRAGMA index_list(表名) 看有没有索引。再配合后续的 EXPLAIN QUERY PLAN,就能快速定位是不是全表扫描。把 PRAGMA 当成你的”数据库体检仪”。

四、类比小结

把 PRAGMA 想成汽车的”仪表盘和设置旋钮”:仪表盘那部分(table_infoindex_listpage_count)让你看清车子当前内部状况;设置旋钮那部分(foreign_keyscache_sizejournal_modesynchronous)让你按行驶环境调参。重要的是记住——很多旋钮(尤其 foreign_keys)是”人上车就要重新拧”的,不会因为上次拧过就永久记住。这也提醒我们:PRAGMA 的”写”动作不等于”改了数据库文件”,它更像改了这次驾驶的偏好,下次换人开车(新连接)依然回到默认设置。

一句话适用场景:想知道数据库”长什么样""有哪些索引""编码和版本是多少”,用读类 PRAGMA;想调并发、安全、性能、外键等行为,用写类 PRAGMA。其中外键开关务必每次连接都开,这是红线级的注意事项。

常见坑(收尾提醒)

PRAGMA 不是标准 SQL,可移植性差:你写在脚本里的 PRAGMA foreign_keys = ON 在 MySQL/PostgreSQL 里完全没有对应物,跨库迁移不要指望它能通用。另外,写类 PRAGMA 大多只影响”当前连接”,重启连接后即失效(不像 CREATE TABLE 那样持久化进文件)。需要持久行为(如默认外键开)应该在应用代码里每次建连后主动设置,而不是依赖某次手动执行。把”该开什么”写进连接初始化逻辑,比靠记忆更可靠。