高い同時実行性を可能にするために、PostgreSQLはマルチバージョン同時実行制御(MVCC)を使用して行を格納します。 しかし、MVCCには更新クエリに対していくつかの欠点があります。 特に、更新では、テーブルに新しいバージョンの行を追加する必要があります。 また、更新された行ごとに新しいインデックスエントリが必要になる可能性があり、古いバージョンの行とそのインデックスエントリを削除するとコストが高くなります。
更新のオーバーヘッドを減らすために、PostgreSQLにはヒープ専用タプルHOTと呼ばれる最適化があります。 この最適化は以下の場合に可能です。
更新は、集約インデックスを除き、テーブルのインデックスによって参照される列を変更しません。 コアのPostgreSQL配布で唯一の集約インデックスメソッドはBRINです。
古い行を含むページには、更新された行に対して十分な空き領域があります。
そのような場合に、ヒープ専用タプルは2つの最適化を提供します。
更新された行を表すために新しいインデックスエントリは必要ありませんが、集約インデックスは更新が必要でしょう。
行が複数回更新されると、最も古いものと最も新しいもの以外の行バージョンは、定期的なバキューム操作を必要とせずに、SELECT
を含む通常の操作で完全に削除されることがあります。
(インデックスは常に元の行バージョンのページアイテム識別子を参照します。
その行バージョンに関連付けられたタプルデータは削除され、そのアイテム識別子は、依然としていくつかの同時トランザクションに見える可能性のある最も古いバージョンを指すリダイレクトに変換されます。
もはや誰にも見えない中間行バージョンは完全に削除され、関連するページアイテム識別子は再利用可能になります。)
テーブルのfillfactor
を減らすことで、HOT更新のための十分なページ領域の可能性を高めることができます。
そうしない場合でも、HOT更新は発生します。
なぜなら、新しい行は新しいページや、新しい行バージョンのために十分な空き領域を持つ既存のページに自然に移動するからです。
システムビューpg_stat_all_tablesは、HOTおよび非HOT更新の発生を監視できます。