本章要回答的三个问题:把数据库塞进自己的进程里,为什么不但没拖慢反而更快?当查询需要的数据比内存还大时,引擎是直接报错还是另有后手?一个以读为主的分析引擎,为什么还需要一套完整的事务机制?
第1章立了选型判断,本章开始拆机器盖子。这件事的现实意义在于:使用层面的绝大多数"玄学现象"——同一查询有时快有时慢、内存明明够用却报溢出、批量导入中途断电数据还在不在——答案都写在架构里。不懂架构的人只能背现象,懂架构的人能推原因。
DuckDB 的架构浓缩起来是三层:进程内的执行层(多线程 morsel 驱动并行)、缓冲管理的内存层(带溢出落盘后手)、乐观并发的事务层(MVCC 快照隔离)。三层各管一段:执行层决定快不快,内存层决定扛不扛得住,事务层决定摔了会不会碎。本章四节加一份排错实录,就是把这三层拆开给你看。
对照开篇三问,本章结束时你应当能做四件事。其一,解释进程内架构省掉了哪些开销、多核并行怎么按数据块切分任务,并能用并行度参数做粗调。其二,配置内存上限与临时目录,理解哪些算子会溢出落盘、代价几何,把"内存溢出"从玄学变成可调参数问题。其三,说清分析场景里事务的真实用途——批量导入的一致性、出错回滚——以及乐观并发在什么情况下会互相踩脚。其四,遇到真实溢出时,按第2.4节的排查路线走完"复现、定位、缓解、根治"四步,而不是盲目加内存。四件事背后共享同一种能力:把现象翻译回机制——同一个"查询变慢",架构读者看到的是溢出、并行不足或统计过期三种可选病因,而现象记录者只能看到"慢"。
这张图有两个观察点。第一,磁盘出现在两条路径上:一条经过缓冲管理器正常读块,一条是内存吃紧时的溢出通道——第2.2节会展开。第二,事务管理器挂在执行层旁边而非存储层下面,因为它的主要工作是给写入操作编版本号、管可见性,而不是锁数据——第2.3节会展开。
| 节号 | 回答哪个问题 | 关键产出 |
|---|---|---|
| 2.1 进程内嵌与多核并行 | 为什么进程内更快,并行怎么切任务 | 并行度与线程参数的调法 |
| 2.2 内存管理与溢出落盘 | 内存装不下怎么办 | 内存上限、临时目录与溢出行为图谱 |
| 2.3 事务处理与ACID取舍 | 分析引擎要事务干什么 | 批量一致性与MVCC边界 |
| 2.4 内存溢出排错实录 | 溢出真发生了怎么走 | 一份四步排查路线与完整案例 |
前三节按"执行、内存、事务"的顺序自上而下拆层,第四节把三节知识拧成一次实战:主线案例的数据翻了几十倍之后,一条聚合查询撞上内存上限,我们陪它走完全程。三层之间还有两组互动值得提前圈出来:并行与内存是此消彼长(线程越多、内存峰值越高,第2.1与2.2节各管一头);事务与存储是里应外合(多版本机制靠第3.3节的检查点回收旧版本)。读的时候留意这些接缝,本章就不是四个孤立知识点,而是一台会互相牵制的机器。
需要第1章的选型常识和基本 SQL;对"线程""进程"有直觉即可,不需要系统编程经验。第2.4节实录里用到的两个命令(查看执行计划、查看内存参数)会现场教,先混个面熟也不影响阅读。
本章与读者的关系值得说破:它不是"给内核开发者的章",而是"给被玄学现象困扰过的分析者的章"。四节内容可以按需进入——被溢出吓过的直接读 2.2 与 2.4,好奇"为什么这么快"的从 2.1 读起,被并发报错绊倒的看 2.3。但有一个推荐顺序的理由:2.1 的并行与 2.2 的内存互相纠缠(并行度越高、内存峰值越高),分开读容易各懂各的,连起来读才能看清它们的相互制约——这个制约关系正是后面调优章(第7.1节)的核心逻辑。
本章拆的是"动态行为"——数据进来之后引擎怎么转。下一章拆"静态布局"——数据躺在磁盘上长什么样。两章合起来才是完整的存储与执行图景,也正好对应第4章查询优化的两大抓手:让执行更省(本章),让读取更少(下章)。主线案例在那之后会迎来第一次大规模提速。