sql >> データベース >  >> RDS >> PostgreSQL

Postgres-XLでのシーケンスとシリアルのパフォーマンス

    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に変更すると、パフォーマンスの違いを目にするユーザーは少なくなります。


    1. ストアドプロシージャから選択する方法

    2. SQLServerのALTERTABLEADDCOLUMNステートメントについて

    3. 異なる行で異なる条件を満たす値を選択しますか?

    4. SQL Server 2019でネイティブにコンパイルされたストアドプロシージャを実行するときの「内部接続の致命的なエラー」(既知のバグ)