PgSQL中优化术语HOT 是 Heap Only Tuple 的缩写。
中文可以翻译为 “仅堆元组”。
- Heap(堆): 在 PostgreSQL 中,表的数据文件被称为“堆文件”。所谓的“堆”就是指表数据本身存储的地方,它是无序的。
- Only(仅): 表示“仅限于”。
- Tuple(元组): 这是 PostgreSQL 内部对“行”(Row)的称呼。
所以,Heap Only Tuple 的字面意思就是“仅存在于堆中的元组”。
这个名称完美地描述了这种优化的核心思想:
一次更新操作(UPDATE)产生的新的行版本(新元组),如果其所有索引键的值都没有改变,那么它就可以被放置在与老元组相同的数据页(Page) 中,并且不需要创建新的索引条目。这个新的元组就只是一个“仅存在于堆(表数据)里”的元组,与索引无关。
为什么 HOT 是一种优化?
在没有 HOT 的情况下,每次 UPDATE
(即使只是更新一个没有索引的字段)都会:
- 在堆文件中创建一个新的行版本。
- 为所有索引创建新的条目,指向这个新的行版本,即使索引字段的值根本没有改变。这会导致索引膨胀,增加维护开销。
而启用 HOT 后,当更新的字段都不属于任何索引键时:
- 在堆文件中创建一个新的行版本(通常在同一数据页)。
- 索引完全不动。所有索引条目仍然指向老的行版本,然后通过堆内部的指针链(一个HOT链)最终找到最新的、有效的行版本。
优点:
- 减少索引膨胀:避免了创建不必要的索引条目,显著减小索引大小。
- 提升性能:减少了
UPDATE
操作需要写入的数据量(不需要写索引),加快了更新速度。同时,因为索引更小,查询速度也可能得到提升。 - 减轻 VACUUM 压力:更少的索引条目意味着
VACUUM
清理死元组时的工作量更小。
如何最大化利用 HOT 更新?
从 pg_stat_user_tables.n_tup_hot_upd
这个计数器中,你可以看到有多少次更新享受到了这个优化。为了促进 HOT 更新,你可以:
- 将经常更新的表设置一个更大的
fillfactor
:fillfactor
默认为 100%,表示数据页将填满。如果设置为 80%,意味着每个数据页会预留 20% 的空间,这样就有更大的概率让新的元组和旧的元组存放在同一个页中,这是触发 HOT 更新的关键条件。ALTER TABLE my_table SET (fillfactor = 80);
- 避免过度索引:只在必要的列上创建索引。每个额外的索引都会降低发生 HOT 更新的概率,因为只要有一个索引的键被更新,就无法使用 HOT。