3

RedHat で Postgres 9.2 を使用しています。次のような表があります。

CREATE TABLE BULK_WI (
    BULK_ID INTEGER NOT NULL,
    USER_ID VARCHAR(20) NOT NULL,
    CHUNK_ID INTEGER,
    STATE VARCHAR(16),
    CONSTRAINT BASE_BULK_WI_PK PRIMARY KEY(BULK_ID,USER_ID)
);
CREATE INDEX BASE_BULK_WI_IDX01 ON BULK_WI(STATE, CHUNK_ID);

バッチ ジョブの一部として、最初に新しい BULK_ID を使用してテーブルに多数の行を追加します。新しいレコードはすべて CHUNK_ID = NULL、STATE = 'PENDING' です。挿入は 500K ~ 1.5M 行です。これが発生したときのテーブルのサイズは、15M レコードを超えます。

挿入後、チャンクでテーブルの処理を開始します。これを行うには、最初に次のチャンクのアイテムをいくつか選択してから、それらを処理します。アイテムの選択は、次のクエリで行われます。

UPDATE BASE_BULK_WI wi SET wi.STATE = 'PROCESSING', wi.CHUNK_ID = $1 
WHERE wi.STATE='PENDING' AND wi.BULK_ID = $2 
AND wi.USER_ID IN 
    (SELECT USER_ID FROM BASE_BULK_WI WHERE BULK_ID = $3 
     AND CHUNK_ID IS NULL AND STATE='PENDING' LIMIT $4 FOR UPDATE)

$1はチャンクの反復ごとに増加し、$2$3は常に同じ (挿入された BULK_ID)、$4は通常 2,000 から 10,000 の間です。

問題は、最初の数チャンクの更新に時間がかかることです。たとえば、制限が 2000 の場合、ほとんどの更新は 1 秒未満で発生しますが、最初の数回は 2 分以上かかります。

これがなぜ起こるのか、そしてそれを修正する方法を理解しようとしています。ドキュメントを読んだ後:

データ ページの一貫性を確保するために、各チェックポイントの後にデータ ページを最初に変更すると、ページ コンテンツ全体がログに記録されます。

チェックポイントと WAL に関連していると思われますが、突き止めることはできませんでした。

助言がありますか?

4

2 に答える 2

5

ANALYZE

autovacuum デーモンも自動的に実行されますが、ANALYZE起動するまでに時間がかかります。UPDATE巨大な の直後に実行する場合は、その間INSERTに実行して統計を更新してください。そうしないと、クエリ プランナーが間違った選択をする可能性があります。ANALYZE

FROM句の代わりにIN

IN大きなサブクエリでは遅いことで有名です。これはより良いパフォーマンスを発揮する可能性があります:

UPDATE base_bulk_wi wi
SET   wi.state = 'PROCESSING'
    , wi.chunk_id = $1 
FROM (
    SELECT user_id, bulk_id 
    FROM   base_bulk_wi
    WHERE  bulk_id = $3 
    AND    chunk_id IS NULL
    AND    state = 'PENDING'
    LIMIT  $4
    FOR    UPDATE
    ) x 
WHERE wi.bulk_id = x.bulk_id
AND   wi.user_id = x.user_id;

インデックス

このような部分インデックスは、あなたのケースに最適なはずです:

CREATE INDEX base_bulk_wi_partial_idx01 ON bulk_wi(chunk_id)
WHERE state = 'PENDING' AND chunk_id IS NULL;

最高のパフォーマンスを得るにINSERT. すでに存在する場合は、前に削除して後で再作成すると役立つ場合があります。

Postgres 9.2 でインデックスのみのスキャンbulk_idを可能にするために、このインデックスに含めることをお勧めします。ただし、サブクエリを使用しているため、とにかくこれはオプションではありません。 FOR UPDATE

user_idinteger代わりに があれば、かなり役に立ちますvarchar。(ユーザー テーブルへの外部キー。) 処理が高速になり、テーブルが小さくなるだけでなく、最小サイズのインデックスに 2 つの整数が完全に収まります。主キーはかなりのメリットがあります。

于 2013-04-21T19:32:25.213 に答える