【SQLite 内核】与 PG / InnoDB 机制对照:进程、WAL、锁、缓冲池

💡 原文中文,约5900字,阅读约需15分钟。
📝

内容提要

本文对比SQLite与PostgreSQL/InnoDB在进程模型、日志、锁和缓冲池四方面的机制差异。SQLite采用嵌入式库、单文件、文件级单写者,无服务器进程和共享缓冲池;PG/InnoDB则有多进程/线程、网络协议和共享缓存。文中强调WAL、snapshot等术语在不同系统中含义不同,需注意区分,并指出SQLite的写串行化与服务器行锁机制本质不同。

🔎

延伸解读

同名不同义:WAL 的三种契约

SQLite 的 WAL 与 PostgreSQL 的 WAL、InnoDB 的 redo 虽然都叫“预写日志”,但目的和运维方式完全不同。SQLite 的 WAL 主要用于单文件库的崩溃恢复和读写重叠,没有复制拓扑;PG 的 WAL 是崩溃恢复和复制的基础,有归档和复制槽;InnoDB 的 redo 则与 undo 配合实现 MVCC。因此,不能把 PG 的 checkpoint、归档经验直接搬到 SQLite 的 wal_checkpoint 上,否则会错位。

锁的层级差异:文件级 vs 行级

SQLite 的锁是文件级的,从 UNLOCKED 到 EXCLUSIVE 的阶梯,写并发受限于单写者;而 PG 和 InnoDB 提供行级锁,支持多写者并发。这意味着“SERIALIZABLE”在 SQLite 中是通过写串行化实现的,与服务器数据库的 MVCC 实现路径不同。因此,不能将行锁经验直接套用到 SQLite 的 SQLITE_BUSY 错误上,需要理解其文件级锁的本质。

缓冲池:共享 vs 每连接

SQLite 的 Page Cache 是每个连接或进程独立的,多进程打开同一文件时通过 change counter 或 WAL-index 使缓存失效,而不是像 PG 的 shared_buffers 或 InnoDB 的 Buffer Pool 那样跨连接共享。因此,调优 SQLite 时,PRAGMA cache_size 只影响当前连接,不是集群级共享内存参数。理解这一差异,有助于避免将服务器数据库的缓冲池调优经验错误地应用到 SQLite。

Q&A

SQLite与PostgreSQL/InnoDB在进程模型上有什么本质区别?

SQLite是嵌入式库,直接嵌入应用进程,通过函数调用访问数据库,没有独立的服务器进程和网络协议;而PostgreSQL采用多进程架构,每个连接一个backend进程,通过共享内存和网络协议通信;InnoDB运行在mysqld的线程模型中,连接与存储引擎通过服务器层解耦。

SQLite的WAL和PostgreSQL的WAL有什么不同?

SQLite的WAL是单文件数据库的写前日志,用于实现读写并发和崩溃恢复,读者可以直接读取WAL帧和主文件快照;PostgreSQL的WAL是崩溃恢复和复制的基础,涉及WAL段文件、归档和复制槽等机制。两者虽然都叫WAL,但目的、实现和运维方式完全不同。

SQLite的锁机制与PostgreSQL/InnoDB的行锁有什么本质不同?

SQLite使用文件级锁,锁状态包括UNLOCKED、SHARED、RESERVED、PENDING和EXCLUSIVE,同一时刻只允许一个写者;而PostgreSQL和InnoDB提供行级锁,支持多写者并发,通过MVCC和锁机制处理冲突。SQLite的写串行化与服务器的行锁机制在并发控制上根本不同。

SQLite的Page Cache与PostgreSQL的shared_buffers有何区别?

SQLite的Page Cache是每个连接或进程私有的,多进程打开同一文件时通过change counter或WAL-index使缓存失效,而不是共享;PostgreSQL的shared_buffers是跨连接共享的服务器资源,所有后端进程共享同一缓冲池,其命中率、刷脏和checkpoint与服务器生命周期绑定。

SQLite的snapshot与PostgreSQL的snapshot isolation是一回事吗?

不是。SQLite的snapshot指的是WAL模式下读者看到的基于检查点的稳定视图,没有多写者并发下的write skew问题;而PostgreSQL的snapshot isolation是多版本并发控制(MVCC)的一部分,支持多写者并发,并可能产生write skew等异常。两者在实现和语义上完全不同。

SQLite的BEGIN IMMEDIATE等同于SERIALIZABLE隔离级别吗?

不等同。BEGIN IMMEDIATE只是提前获取RESERVED锁,以减少后续升级锁失败的概率,并不改变隔离级别的语义。SQLite的隔离级别实现基于写串行化,与服务器数据库的SERIALIZABLE实现路径不同。

SQLite与PostgreSQL/InnoDB在崩溃恢复机制上有哪些共同点和差异?

共同点是都使用写前日志(WAL或redo)来保证原子提交和崩溃恢复。差异在于SQLite的WAL是单文件数据库的日志,用于读写并发和恢复;PostgreSQL的WAL还用于复制;InnoDB的redo/undo与SQLite的journal更接近,但实现细节和运维方式不同。

🏷️

标签

➡️

继续阅读