Skip to content

一条 SQL 的旅程:查询、事务与恢复 ​

数据库向应用提供数据模型、查询与事务承诺。它内部仍要处理内存、磁盘、并发和失败;SQL 隐藏的是执行选择,而不是这些成本。本篇沿一条查询和一次更新建立完整流程,参考 CMU 15-445。

从文本到执行计划 ​

sql
SELECT name FROM students
WHERE department = 'CS' AND year >= 3
ORDER BY name LIMIT 20;

解析器建立语法树;绑定阶段查找表、列、类型与权限;逻辑计划表达过滤、投影、排序等操作;优化器根据统计信息和代价估计选择物理算子;执行器实际获取记录并返回结果。数据库可以选索引扫描,也可以顺序扫描,SQL 文本本身不指定它必须采用哪一种。

flowchart LR
  A[SQL 文本] --> B[解析与绑定]
  B --> C[逻辑计划]
  C --> D[代价优化]
  D --> E[物理执行计划]
  E --> F[缓冲池与存储页]
  F --> G[结果行]
查看流程图文本
flowchart LR
  A[SQL 文本] --> B[解析与绑定]
  B --> C[逻辑计划]
  C --> D[代价优化]
  D --> E[物理执行计划]
  E --> F[缓冲池与存储页]
  F --> G[结果行]

若过滤条件只选中很少行,索引可减少读取;若多数行都符合条件,索引定位后反复回表可能比顺序扫描更贵。优化器依赖行数、分布、相关性等估计;统计过时会让“看起来便宜”的计划实际很慢。因此调优应看执行计划和实际行数,而不仅看是否“用了索引”。

索引把什么成本降下来 ​

B+ 树用较大扇出降低树高,内部节点导航、叶子保存有序键及记录引用或数据。若把根、下一层内部节点、叶子算作三层,内部节点扇出约 100,则可连接约 1002=104 个叶页;若每个叶页再容纳约 100 个条目,总容量才约为百万条目。实际容量还取决于页大小、条目布局与节点填充率。范围查询可沿叶子顺序扫描。

复合索引 (department, year) 按元组字典序排列,因此适合先约束 department 再约束 year;它并不会自动满足 ORDER BY name。覆盖索引若已包含查询所需列,可以减少回表。每增加一个索引也增加写入、空间和维护成本。

LSM 树把写入先积累到内存结构,再刷成有序磁盘文件,通过 compaction 合并。它以额外的合并写入和查询多个层次等成本换取写入组织优势。Bloom filter 可以快速排除“肯定不存在”的文件,但可能误报存在;它不能返回完整记录,也不能取代范围索引。

缓冲池与页 ​

磁盘以块传输,数据库把热页缓存在缓冲池。页被访问时需要固定或引用保护,避免操作尚未完成就被淘汰;脏页需要写回。页闩锁保护短时内存结构,事务锁约束业务读写可见性,作用范围和生命周期不同。把所有锁都叫 mutex 会掩盖这些区别。

并发:MVCC 保留多个版本 ​

MVCC 让读取依据快照选择可见版本,减少读写直接互相阻塞。更新产生新版本,旧版本在不再被活动快照需要后才可回收。长事务可能阻碍旧版本清理,导致膨胀;“读不阻塞写”不意味着没有任何锁或写写冲突。

隔离级别决定允许观察哪些异常。读已提交允许同一事务的不同语句看到不同已提交状态;可重复读或快照隔离通常提供更稳定视图,但不同数据库具体语义不同。快照隔离可能出现 write skew:两笔事务分别更新不同记录,却共同破坏跨行约束。需要可串行化保证、显式锁或重新设计约束。

更新何时可以称为持久 ​

WAL 的核心顺序是:与某个数据页更新相关的日志,必须先于该脏页落盘。否则断电后看到了部分新数据,却没有足够的日志解释或恢复它。事务提交一般还需要把提交所需日志刷到稳定存储,具体 durability 设置会影响承诺。

数据页可以稍后批量刷盘,崩溃后根据日志 redo 已应当保留的更改,并按具体恢复算法处理未完成事务。checkpoint 缩小恢复范围,但不能简单理解成“数据库所有数据在一个瞬间全部一致写完”。文件系统日志与数据库 WAL 保护的对象不同,文件系统保证结构完整不自动等于应用事务完整。

三个工程问题 ​

  1. 慢查询:是扫描太多行、排序溢出、随机 I/O、锁等待,还是客户端取数慢?
  2. 连接过多:更多连接不一定更多吞吐,可能只是更大竞争;需要连接池与背压。
  3. 重复提交:事务重试可能必要,应用需处理序列化失败;外部副作用应考虑幂等和 outbox。
自测:给每一列都建索引,查询是否一定更快?

不是。索引占空间且增加写维护成本;选择性低、访问大部分表或统计错误时,扫描更合理。组合索引的顺序也决定可利用的前缀,需要针对实际查询计划分析。

来源:CMU 数据库课程、PostgreSQL 事务隔离、PostgreSQL WAL。与跨分片事务对照阅读。