Postgres-XLでは、シーケンスはグローバルトランザクションマネージャー(GTM)で維持され、複数のノードからインクリメントされたときに競合しない値が割り当てられるようにします。これにより、シリアル列を持つテーブルで数千のINSERTを実行し、シーケンスを一度に1つずつインクリメントし、INSERTごとにGTMへのネットワークラウンドトリップを行うクエリに大きなオーバーヘッドが追加されます。
最近のブログのShaunThomasは、バニラPostgreSQLと比較してPostgres-XLでINSERTの実行速度が大幅に遅いことについて不満を述べています。シーケンスのパフォーマンスを改善する方法はすでにありますが、それは明らかに十分に宣伝されていません。施設を説明する良い機会だと思いました。
Postgres-XLは、 sequence_rangeと呼ばれるユーザー設定可能なGUCを提供します 。すべてのバックエンドは、このGUCによって制御されるシーケンス値のブロックを要求します。 COPYはPostgresでデータを一括ロードするために一般的に使用されているため、Postgres-XLはCOPY操作中にこのGUCを自動的にオーバーライドし、1000に設定するため、COPYのパフォーマンスが大幅に向上します。残念ながら、通常のINSERTの場合、デフォルトは1であり、ユーザーが明示的に sequence_range を設定しない限り、 適度に高い値にすると、INSERTのパフォーマンスが低下します。これは、Shaunがブログ投稿で使用したものと同じサンプルスキーマを使用した例です。
CREATE TABLE sensor_log ( sensor_log_id SERIAL PRIMARY KEY, location VARCHAR NOT NULL, reading BIGINT NOT NULL, reading_date TIMESTAMP NOT NULL ) DISTRIBUTE BY HASH (sensor_log_id); postgres=# \timing Timing is on. postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 12067.911 ms postgres=# set sequence_range TO 1000; SET Time: 1.231 ms postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 397.406 ms
したがって、 sequence_rangeを適切に設定することによって 1000にすると、INSERTクエリのパフォーマンスは約30倍向上しました。
この機能が追加されたとき、sequence_range GUCのデフォルト値は1に設定されていました。これは、シーケンス値に穴を残す可能性があるためです。しかし、非常に一般的なユースケースのパフォーマンスへの影響を見て、デフォルトを1000に増やすことにしました。これは、リポジトリのXL9_5_STABLEブランチにコミットされました。
sequence_range の値が高い場合は、注意することが重要です。 シーケンスとシリアルのパフォーマンスが向上します。シーケンス範囲はバックエンドレベルでキャッシュされるため、シーケンス範囲に大きな穴が残る可能性もあります。この問題に対処するために、Postgres-XLは、シーケンス作成時に使用される指定されたCACHEパラメーター値から開始し、シーケンスが非常に高速で消費されている場合は毎回2倍にします(sequence_rangeによって制限されます)。
同様の改善は、シーケンスのCACHEパラメータ値を増やして、シーケンス値のチャンクがバックエンドレベルでキャッシュされるようにすることでも実現できます。次の例は、シリアル列に対してこれを行う方法を示しています。ただし、 sequence_range GUCは、グローバルデフォルトをオーバーライドする簡単な方法を提供し、シーケンスが非常に急速にインクリメントされている場合にのみシーケンスがキャッシュされるようにします。
postgres=# ALTER SEQUENCE sensor_log_sensor_log_id_seq CACHE 1000; ALTER SEQUENCE Time: 8.683 ms postgres=# SET sequence_range TO 1; SET Time: 2.341 ms postgres=# INSERT INTO sensor_log (location, reading, reading_date) SELECT s.id % 1000, s.id % 100, now() - (s.id || 's')::INTERVAL FROM generate_series(1, 40000) s(id); INSERT 0 40000 Time: 418.068 ms
パフォーマンスを向上させるために、これらの手法のいずれかを選択できます。ただし、 sequence_rangeのデフォルト値は を1000に変更すると、パフォーマンスの違いを目にするユーザーは少なくなります。