上篇:PostgreSQL
1. 排序(Tuplesort / work_mem)
| 结构 | 层级 | 作用 |
|---|---|---|
| Tuplesortstate | backend MemoryContext | 单次 Sort 节点工作区 |
| BufFile / logtape | pgsql_tmp |
超过 work_mem 落盘 |
| Shared Buffers | 共享内存 | 表数据页;不承担排序工作区 |
- 多 Sort 节点 → 可能多份
work_mem(× 并发)。 EXPLAIN ANALYZE:quicksortvsexternal merge(spill)。
参数:work_mem
2. 等值连接(Hash Join)
等值 JOIN:Build 小表 HashJoinTable → Probe 大表。无索引时常用;有索引时多为 Index Nested Loop。
| 结构 | 说明 |
|---|---|
| HashJoinTable | nodeHashjoin.c,常在 hashCxt |
| BufFile | 过大时 batch 落盘 |
参数:work_mem;PG 13+ 可用 hash_mem_multiplier。
EXPLAIN:Hash Join → Hash → 子扫描。
3. 排序 vs 临时表(Tuplesort vs Materialize)
| Tuplesort | 临时表 / 物化 | |
|---|---|---|
| 用途 | 对已有行 排序 | HashAggregate、Materialize、临时 heap |
| 典型 | Sort 节点 |
GROUP BY、子查询物化 |
| 页缓存 | — | 临时关系走 local buffers(temp_buffers) |
计划组合
| 现象 | 计划节点 |
|---|---|
| 只排序 | Sort |
| 只物化/聚合 | HashAggregate / Materialize |
| 先聚合再排序 | HashAggregate → Sort |
案例 1:只排序
|
|
索引满足顺序 → 可能无 Sort;否则 Index Scan + Sort,一般无 Materialize。
案例 2:只临时表/聚合
|
|
常见 HashAggregate 或 GroupAggregate,无 ORDER BY 则常无 Sort。
|
|
子查询 → Materialize;外层过滤,无 Sort。
案例 3:临时表 + 排序
|
|
HashAggregate → Sort:先按 city 聚合,再对 (city,cnt) 排序。
4. 缓冲池(Shared Buffers)
数据文件在 $PGDATA/base/ 等路径。读页:磁盘 → OS Page Cache → Shared Buffers。
| 项 | 说明 |
|---|---|
| 结构 | Shared Buffers |
| 淘汰 | clock-sweep / LRU 类策略 |
| 参数 | shared_buffers |
| 双缓存 | 与 OS 页缓存可能重复,常适度设 shared_buffers |
执行层不在 Shared Buffers 里:Tuplesort、HashJoinTable、临时表(用 local buffers)。
命中率 SQL(须小数除法):
|
|
|
|
整数相除 (blks_hit)/(blks_hit+blks_read) 会得到 0。
下篇:MySQL 8.0
1. 排序(sort buffer / filesort)
| 结构 | 层级 | 作用 |
|---|---|---|
| sort buffer | 连接线程 | filesort 待排序行 |
| 临时文件 | tmpdir |
buffer 不够时归并 |
| Buffer Pool | InnoDB | 读表页;不是排序区 |
Using filesort:Server 层排序;不一定写盘。
参数:sort_buffer_size
文档:10.12.3.1
2. 连接(Hash Join / Join Buffer)
一次 JOIN 只走一种主路径:
| 算法 | 内存 | 参数 |
|---|---|---|
| Nested Loop + 索引 | 无专用块 | 索引 |
| BNL / BKA | Join Buffer(外表一批行) | join_buffer_size |
| Hash Join(8.0.18+) | 哈希表(键→行) | ≠ Join Buffer |
- Join Buffer:BNL 缓存驱动表行,不是 Hash Join 哈希表。
Using join buffer (hash join)与(Block Nested Loop)不同算法。
Hash 表过大 → tmpdir chunk 落盘。
文档:Hash Joins
3. sort buffer vs 内部临时表(TempTable)
| sort buffer | 内部临时表 | |
|---|---|---|
| 用途 | 排序 | GROUP BY、派生物化、去重等 |
| Extra | Using filesort |
Using temporary |
| 引擎 | — | 默认 TempTable;过大 → InnoDB 磁盘临时表 |
Extra 组合
| Extra | 含义 |
|---|---|
Using filesort |
只需排序 |
Using temporary |
只需中间表,无需再排序 |
Using temporary; Using filesort |
先写临时表,再排序 |
案例 1:仅 filesort
|
|
|
|
有合适索引时可能无 filesort、无 temporary。
案例 2:仅 temporary
|
|
|
|
无 ORDER BY → 通常无 filesort。
案例 3:temporary + filesort
|
|
|
|
GROUP BY 不能靠 sort buffer 累加;聚合后的行集无序,必须再 filesort。
案例 4:DISTINCT + ORDER BY
|
|
常 temporary + filesort(以 EXPLAIN 为准)。
监控:Created_tmp_tables、Created_tmp_disk_tables、Sort_merge_passes
文档:10.4.4
4. 缓冲池(Buffer Pool)
表空间为 .ibd 等文件。读页:磁盘 → OS Page Cache → Buffer Pool(Linux 上常 O_DIRECT 减轻双缓存)。
| 项 | 说明 |
|---|---|
| 结构 | Buffer Pool |
| 热点 | LRU young / old(midpoint 插入) |
| 参数 | innodb_buffer_pool_size |
不在 Buffer Pool:sort buffer、Join Buffer、Hash Join 表、TempTable 数据;undo 页读入后 在 Buffer Pool。
文档:17.5.1
对照(简表)
| 主题 | PostgreSQL | MySQL 8.0 |
|---|---|---|
| 排序 | Tuplesort / work_mem |
sort buffer / sort_buffer_size |
| 等值连接 | HashJoinTable | Hash Join 哈希表 |
| 外表批量 | — | Join Buffer(BNL) |
| 中间结果 | Materialize / HashAggregate | TempTable |
| 表页 | Shared Buffers | Buffer Pool |
InnoDB 全进程内存(redo、undo、binlog):进程内存总图