上篇:PostgreSQL

1. 排序(Tuplesort / work_mem)

结构 层级 作用
Tuplesortstate backend MemoryContext 单次 Sort 节点工作区
BufFile / logtape pgsql_tmp 超过 work_mem 落盘
Shared Buffers 共享内存 表数据页;承担排序工作区
  • 多 Sort 节点 → 可能多份 work_mem(× 并发)。
  • EXPLAIN ANALYZEquicksort vs external merge(spill)。

参数work_mem


2. 等值连接(Hash Join)

等值 JOINBuild 小表 HashJoinTableProbe 大表。无索引时常用;有索引时多为 Index Nested Loop。

结构 说明
HashJoinTable nodeHashjoin.c,常在 hashCxt
BufFile 过大时 batch 落盘

参数work_mem;PG 13+ 可用 hash_mem_multiplier

EXPLAINHash JoinHash → 子扫描。


3. 排序 vs 临时表(Tuplesort vs Materialize)

Tuplesort 临时表 / 物化
用途 对已有行 排序 HashAggregateMaterialize、临时 heap
典型 Sort 节点 GROUP BY、子查询物化
页缓存 临时关系走 local bufferstemp_buffers

计划组合

现象 计划节点
只排序 Sort
只物化/聚合 HashAggregate / Materialize
先聚合再排序 HashAggregateSort

案例 1:只排序

1
2
3
4
5
SELECT id, created_at
FROM orders
WHERE user_id = 100
ORDER BY created_at DESC
LIMIT 20;

索引满足顺序 → 可能无 Sort;否则 Index Scan + Sort,一般无 Materialize

案例 2:只临时表/聚合

1
2
3
SELECT city, COUNT(*) AS cnt
FROM orders
GROUP BY city;

常见 HashAggregateGroupAggregate,无 ORDER BY 则常无 Sort

1
2
3
SELECT * FROM (
    SELECT user_id, SUM(amount) AS s FROM orders GROUP BY user_id
) AS t WHERE s > 1000;

子查询 → Materialize;外层过滤,无 Sort

案例 3:临时表 + 排序

1
2
3
4
SELECT city, COUNT(*) AS cnt
FROM orders
GROUP BY city
ORDER BY cnt DESC;

HashAggregateSort:先按 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(须小数除法):

1
2
3
4
5
6
7
SELECT
    datname,
    blks_hit,
    blks_read,
    round(100.0 * blks_hit / nullif(blks_hit + blks_read, 0), 2) AS cache_hit_percent
FROM pg_stat_database
WHERE datname = current_database();
1
2
3
4
SELECT datname,
       blks_hit::numeric / nullif(blks_hit + blks_read, 0) AS cache_hit_ratio
FROM pg_stat_database
WHERE datname = current_database();

整数相除 (blks_hit)/(blks_hit+blks_read) 会得到 0

文档work_mempg_stat_database


下篇: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

1
2
3
4
5
SELECT id, created_at, amount
FROM orders
WHERE user_id = 100
ORDER BY created_at DESC
LIMIT 20;
1
扫描 → sort buffer 排序 → LIMIT

有合适索引时可能无 filesort、无 temporary。

案例 2:仅 temporary

1
2
3
SELECT city, COUNT(*) AS cnt
FROM orders
GROUP BY city;
1
扫描 → TempTable 按 city 累加 → 输出

ORDER BY → 通常无 filesort。

案例 3:temporary + filesort

1
2
3
4
SELECT city, COUNT(*) AS cnt
FROM orders
GROUP BY city
ORDER BY cnt DESC;
1
2
阶段1:TempTable 聚合     ← Using temporary
阶段2:sort buffer 按 cnt 排序 ← Using filesort

GROUP BY 不能靠 sort buffer 累加;聚合后的行集无序,必须再 filesort。

案例 4:DISTINCT + ORDER BY

1
SELECT DISTINCT city FROM orders ORDER BY city;

常 temporary + filesort(以 EXPLAIN 为准)。

监控Created_tmp_tablesCreated_tmp_disk_tablesSort_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):进程内存总图