PosgreSQLで非常に大きくなるテーブルの主キーとして、非シーケンシャルUUIDを使用することによるパフォーマンスへの影響について疑問に思っています。
テーブルレコードにクラスター化されたストレージを使用するDBMSでは、テーブルが大きすぎると、UUIDを使用すると、挿入を実行するデータページを見つけるためにディスクから読み取る必要があるため、挿入のコストが増加することが想定されます。メモリに保持します。私が理解しているように、Postgresは挿入時に行クラスタリングを維持しないため、PostgresではUUID PKを使用してもその挿入のパフォーマンスが低下しないと想像します。
しかし、テーブルが大きくなると、主キー制約が作成するインデックスへの挿入は、新しいデータの挿入時にインデックスを更新するために常にディスクから読み取られる必要があるため、より高価になると思います。一方、順次キーでは、インデックスは常にメモリにある先端でのみ更新されます。
インデックスへのパフォーマンスの影響を正しく理解していると仮定すると、それを修正する方法はありますか?それとも、UUIDがパーティション化されていない大きなテーブルで単に適切なPKではないのですか?
私が理解しているように、Postgresは挿入時に行クラスタリングを維持しません
現時点で修正しています。残念ながら。
したがって、PostgresでUUID PKを使用しても、その挿入のパフォーマンスが低下しないと思います。
PKを維持する必要があるため、および挿入されたタプルが大きいため、依然としてパフォーマンスコストがかかります。
Uuidは一般的な32ビット整数の合成キーの4倍の幅があるため、書き込む行は12バイト大きく、特定の量のRAMに格納できる行の数は少なくなります。
主キーを実装するbツリーインデックスは4倍(32ビットキーに対して)であり、検索に時間がかかり、キャッシュするためにより多くのメモリを必要とします。また、より頻繁なページ分割も必要です。
書き込みはインデックス内でランダムになる傾向があり、最近アクセスされたホットな行に追加されません
[インデックスのパフォーマンスへの影響]を修正する方法はありますか、それとも、UUIDはパーティション化されていない大きなテーブルで単にPKとして適切ではないのですか?
UUIDキーが必要な場合は、UUIDキーが必要です。必要がない場合は使用しないでください。ただし、合成キーの中央ソースに依存できず、使用する適切な自然キーがない場合は、それでも問題ありません。
書き込みを1つのパーティションに制限できない限り、パーティション化はあまり役に立ちません。また、一度に1つのパーティションにのみ書き込む場合は、キーの検索で制約の除外を有効に使用できないため、クエリを実行するときに、すべてのパーティションのインデックスでキーを検索する必要があります。あなたのUUIDが複合キーの一部を形成していて、複合キーの他の部分に分割できる場合にのみ、それが有用であることがわかります。
full_page_writes
オプションが有効になっているUUID列にbtreeインデックスがある場合、より多くのWALが生成されることを言及しておく必要があります。これはUUIDのランダム性が原因で発生します。値は連続していないため、各挿入は完全に新しいリーフインデックスリーフページに接触する可能性があります。詳しくは フルページ書き込みの影響について の記事を参照してください。