SQLite学习笔记

参数查询

PRAGMA

PRAGMA 是 SQLite 中一种非常特殊的指令,你可以把它理解为SQLite 的“控制面板”或“调节旋钮”

与标准的 SQL 语句(如 SELECT, INSERT)不同,PRAGMA 是 SQLite 独有的,主要用于:

  1. 修改数据库引擎的行为(如:开启外键、设置缓存大小)。
  2. 查询数据库的元数据(如:查看表结构、索引列表)。
  3. 执行维护操作(如:完整性检查、清理空间)。

以下是 SQLite 中常用 PRAGMA 命令的详细说明,按功能分类整理:

查询元数据(数据字典)

命令 说明 示例
table_info 获取表的列信息(列名、类型、是否主键等)。 PRAGMA table_info('user_table');
index_list 列出表上的所有索引。 PRAGMA index_list('user_table');
index_info 查看某个具体索引包含哪些列。 PRAGMA index_info('idx_user_name');
database_list 列出当前挂载的所有数据库(主库及附加库)。 PRAGMA database_list;
foreign_key_list 查看表定义的外键信息。 PRAGMA foreign_key_list('order_table');

性能与缓存优化

这些设置通常用于提升数据库的读写速度,建议在数据库连接建立时进行配置。

命令 说明 推荐设置/示例
cache_size 设置内存中缓存的数据库页数。值越大,读取越快,但占用内存越多。 PRAGMA cache_size = -2000; (负数表示KB,即2MB)
temp_store 控制临时表存储位置。 PRAGMA temp_store = MEMORY; (存入内存,速度更快)
synchronous 控制数据写入磁盘的同步级别。
FULL: 最安全(默认),最慢。
NORMAL: 平衡。
OFF: 最快,但在断电时可能丢失数据。
PRAGMA synchronous = NORMAL;
journal_mode 设置日志模式。
DELETE: 默认模式。
WAL: 推荐。允许读写并发,性能更好。
PRAGMA journal_mode = WAL;

数据完整性与安全

这些命令关乎数据的正确性和约束。

命令 说明 示例
foreign_keys 重要。SQLite 默认强制执行外键约束,必须手动开启。 PRAGMA foreign_keys = ON;
integrity_check 检查整个数据库文件的完整性,看是否有损坏。 PRAGMA integrity_check;
encoding 查看或设置数据库的字符编码(UTF-8, UTF-16 等)。 PRAGMA encoding;

维护与清理

用于数据库文件的瘦身和重构。

命令 说明 示例
auto_vacuum 设置自动回收删除数据后的空闲空间。
NONE: 默认,不自动回收。
FULL: 自动回收。
INCREMENTAL: 增量回收。
PRAGMA auto_vacuum = FULL;
page_size 设置数据库页大小(通常为 1024, 2048, 4096 等)。 PRAGMA page_size = 4096;
wal_checkpoint 在 WAL 模式下,强制将日志文件的数据写回主数据库文件。 PRAGMA wal_checkpoint;

语法与注意事项

PRAGMA 命令有两种主要形式:

  1. 读取值PRAGMA 命令名;
  2. 设置值PRAGMA 命令名 = 值;PRAGMA 命令名(值);

关键注意事项:

  1. 作用域:大多数 PRAGMA 设置(如 cache_size, foreign_keys仅对当前数据库连接有效。如果你关闭了连接再重新打开,设置会恢复默认值。因此,通常建议在每次建立连接后立即执行必要的 PRAGMA 设置。
  2. 静默失败:如果你拼写错了一个 PRAGMA 命令,SQLite 不会报错,而是会直接忽略它。
  3. 不可逆性:某些设置(如 page_sizeencoding)只能在数据库创建之初设置,一旦有数据写入,通常无法更改(除非导出数据重建库)。

生产环境推荐配置清单

-- 1. 核心并发与性能配置
PRAGMA journal_mode = WAL;				-- 开启预写日志,支持高并发
PRAGMA synchronous = NORMAL;			-- 平衡速度与安全性
PRAGMA busy_timeout = 5000;
PRAGMA wal_autocheckpoint = 1000;

-- 2. 内存与缓存优化
PRAGMA cache_size = -20000;				-- 分配 20MB 缓存
PRAGMA mmap_size = 268435456;
PRAGMA temp_store = MEMORY;				-- 临时表存内存

-- 3. 数据完整性
PRAGMA foreign_keys = ON;				-- 强制开启外键约束

详细配置原因解析

1. 开启预写日志模式

  • 命令: PRAGMA journal_mode = WAL;
  • 原因: 这是 SQLite 生产环境最重要的配置。
    • 默认行为 (DELETE): 每次写入时,SQLite 会锁定整个数据库文件,导致读写互斥(写入时不能读取,读取时不能写入)。
    • WAL 模式: 写入操作会先写入一个单独的 -wal 文件。这意味着读取者不会阻塞写入者,写入者也不会阻塞读取者。对于 Web 服务等高并发场景,这能带来数量级的性能提升。

2. 平衡同步策略

  • 命令: PRAGMA synchronous = NORMAL;
  • 原因: 在“速度”与“极端安全性”之间取得平衡。
    • FULL (默认): 每次事务提交都强制刷盘(fsync),极其安全但速度慢,尤其是在机械硬盘上。
    • OFF: 仅由操作系统决定何时刷盘,速度最快,但断电可能导致数据库损坏。
    • NORMAL: 推荐。仅在 WAL 模式下切换检查点(Checkpoint)时进行 fsync。如果系统崩溃,数据通常能保持完整;只有在操作系统崩溃(不仅仅是断电)时才会有风险。这是现代生产环境的主流选择。

3. 解决“数据库被锁定”问题

  • 命令: PRAGMA busy_timeout = 5000;
  • 原因: 防止应用程序因短暂的锁冲突而直接报错崩溃。
    • 即使开启了 WAL 模式,在极高并发写入或进行 Schema 变更时,仍可能出现锁竞争。
    • 设置 5000 (毫秒) 意味着:如果数据库正忙,SQLite 会等待 5 秒,直到锁释放。如果 5 秒后仍无法获取锁,才抛出 SQLITE_BUSY 错误。这能显著提高系统的容错率。

4. 优化 WAL 检查点频率

  • 命令: PRAGMA wal_autocheckpoint = 1000;
  • 原因: 控制 -wal文件的大小和回写频率。
    • 该参数定义了 WAL 文件中积累多少页(Page)后触发一次检查点(将数据从 WAL 文件合并回主数据库文件)。
    • 默认值通常较大(1000页)。设置为 1000 左右可以防止 WAL 文件无限增长占用过多磁盘空间,同时保证数据能及时落盘。

5. 增大页缓存

  • 命令: PRAGMA cache_size = -20000;
  • 原因: 减少磁盘 I/O,提升查询速度。
    • SQLite 会在内存中缓存一部分数据库页。
    • 默认值通常较小(约 2MB)。
    • 负数单位是 KB-20000 表示分配约 20MB 的内存用于缓存。对于内存充足的服务器,适当增大此值(如 50MB-100MB)可以显著提高热点数据的读取性能。

6. 启用内存映射 (MMAP)

  • 命令: PRAGMA mmap_size = 268435456;
  • 原因: 利用操作系统特性加速读取。
    • 该值设置为 256MB (268435456 字节)。
    • MMAP 允许 SQLite 直接将数据库文件映射到进程的虚拟内存地址空间。读取数据时,无需调用 read() 系统调用,而是直接访问内存指针,由操作系统负责按需加载物理页。这对于只读查询密集型的应用非常有效。

7. 临时表存内存

  • 命令: PRAGMA temp_store = MEMORY;
  • 原因: 加速排序和复杂查询。
    • 当执行 ORDER BYGROUP BY 或创建临时表时,如果数据量大,SQLite 会使用磁盘文件。
    • 强制设为 MEMORY 后,这些临时操作直接在 RAM 中进行,避免了频繁的磁盘读写。

8. 强制开启外键

  • 命令: PRAGMA foreign_keys = ON;
  • 原因: 保证数据逻辑一致性。
    • SQLite 为了兼容旧版本,默认执行外键约束。
    • 在生产环境中,必须显式开启它,以防止出现“孤儿数据”(例如:订单表里引用了一个不存在的用户 ID)。

配置前后对比

特性 默认配置 生产环境推荐配置 影响
并发能力 低 (读写互斥) (读写并发) 支持多用户同时访问
写入性能 较慢 (频繁 fsync) (NORMAL + WAL) 响应时间显著降低
稳定性 容易报 BUSY 错误 稳定 (自动重试) 减少程序崩溃
内存利用 保守 (缓存小) 积极 (大缓存+MMAP) 充分利用服务器内存

补充建议

  1. 持久化设置:除了 foreign_keysbusy_timeout 必须在每次连接时设置外,其他设置(如 journal_mode, synchronous)一旦设置,通常会保存在数据库文件中,下次重启依然有效。但为了保险起见,在代码初始化时统一设置一遍是最好的习惯。
  2. 定期维护:在 WAL 模式下,建议定期(如每天低峰期)运行 PRAGMA wal_checkpoint(TRUNCATE); 来回收磁盘空间,或者让应用程序在启动时检查 WAL 文件大小。

数据字典

sqlite_master

字段名 数据类型 含义 说明
type TEXT 对象类型 记录该条目属于哪种数据库对象。常见的取值有: 'table':普通表 'index':索引 'view':视图 'trigger':触发器
name TEXT 对象名称 该对象的实际名字。例如表名、索引名或触发器名。
tbl_name TEXT 所属表名 对于本身,这个字段通常与 name 相同。
对于索引触发器,这个字段记录它们是属于哪张表的。
rootpage INTEGER 根页号 该对象在数据库文件中存储位置的起始页编号。SQLite 底层使用 B-Tree 结构,这个值指向 B-Tree 的根节点页。对于视图和触发器,该值通常为 0 或 NULL。
sql TEXT 创建语句 这是最有用的字段。它存储了创建该对象时使用的原始 SQL 语句(例如 CREATE TABLE ...)。
如果是系统自动创建的索引(如主键索引),该字段可能为 NULL

sqlite_master 表是只读的。你不能直接对它执行 INSERTUPDATEDELETE 操作。当你执行 CREATE TABLEDROP TABLE 等命令时,SQLite 会自动维护这张表的内容。

sqlite_temp_master

结构与sqlite_master 表类似

如果你创建了临时表(CREATE TEMP TABLE),它们不会出现在 sqlite_master 中,而是存储在 sqlite_temp_master表中。

对象信息查询

查看所有用户创建的表

-- 系统内部也会有一些以 sqlite_ 开头的表,通常我们需要过滤掉它们
SELECT name, sql 
FROM sqlite_master 
WHERE type='table' AND name NOT LIKE 'sqlite_%';

获取某张表的建表语句

-- 建表DDL
SELECT sql 
FROM sqlite_master 
WHERE type='table' AND name='你的表名';

-- 表字段列表
PRAGMA table_info('contacts');

查看某张表下的所有索引

SELECT name, sql 
FROM sqlite_master 
WHERE type='index' AND tbl_name='你的表名';

-- 列出表的所有索引
PRAGMA index_list('tablename');

-- 查看某个具体索引包含哪些列
PRAGMA index_info('索引名称');

参考资料

https://www.runoob.com/sqlite/sqlite-tutorial.html

posted @ 2026-03-29 22:32  kahnyao  阅读(12)  评论(0)    收藏  举报