PostgreSQL 8.3をストレージバックエンド(Pythonとpsycopg2を使用)として使用する、特定のアプリケーションがあります。重要なテーブルに対して実行する操作は、挿入または更新の大多数(ほとんどは削除または選択)にあります。PostgreSQLの更新/置換操作をどのように高速化できますか?
私たちは正当な理由から、適切に動作する独自のData Mapperレイヤーを作成しましたが、1つの大きなボトルネック、つまり更新のパフォーマンスがあります。もちろん、私はupdate/replaceシナリオが '空のテーブルへの挿入'のようにスピーディーであるとは思っていませんが、ちょっと近づけばいいですね。このシステムは、私は私のテストで単語「置き換える」を使用する用語で見ることができる我々は常に更新時に各列のすべてのフィールドを設定して同時更新
から自由であることを
は注意。
を更新するために、行の配列をとる
replace()
プロシージャを作成します:私はこれまで、当社の更新問題への2つのアプローチを試してみたCREATE OR REPLACE FUNCTION replace_item(data item[]) RETURNS VOID AS $$ BEGIN FOR i IN COALESCE(array_lower(data,1),0) .. COALESCE(array_upper(data,1),-1) LOOP UPDATE item SET a0=data[i].a0,a1=data[i].a1,a2=data[i].a2 WHERE key=data[i].key; END LOOP; END; $$ LANGUAGE plpgsql
が
insert_or_replace
ルールを作成するようにすべてのものが、時折削除となる多列が挿入CREATE RULE "insert_or_replace" AS ON INSERT TO "item" WHERE EXISTS(SELECT 1 FROM item WHERE key=NEW.key) DO INSTEAD (UPDATE item SET a0=NEW.a0,a1=NEW.a1,a2=NEW.a2 WHERE key=NEW.key);
のThすべてのテストは、データベースと同じコンピュータ上で実行されている
- :テスト実行に関する
Multi-row insert : 50000 items inserted in 1.32 seconds averaging 37807.84 items/s executemany() update : 50000 items updated in 26.67 seconds averaging 1874.57 items/s update_andres : 50000 items updated in 3.84 seconds averaging 13028.51 items/s update_merlin83 (i/d/i) : 50000 items updated in 1.29 seconds averaging 38780.46 items/s update_merlin83 (i/u) : 50000 items updated in 1.24 seconds averaging 40313.28 items/s replace_item() procedure : 50000 items replaced in 3.10 seconds averaging 16151.42 items/s Multi-row insert_or_replace: 50000 items inserted in 2.73 seconds averaging 18296.30 items/s Multi-row insert_or_replace: 50000 items replaced in 2.02 seconds averaging 24729.94 items/s
ランダムノート:後者が遅くビットを挿入しますが、両方がアップデートに公平なビットをスピードアップESE住む。 localhostに接続しています。
- 挿入と更新は、それぞれ独自のトランザクション(UPDATED)で送信された500項目のバッチでデータベースに適用されます。
- すべての更新/置換テストでは、データベースにすでにある値と同じ値が使用されていました。
- psycopg2 adapt()関数を使用して、すべてのデータがエスケープされました。
- すべてのテーブルが切り捨てられ、使用前に真空ある(のみ切り捨てが起こった以前の実行中に、を追加しました)
テーブルは次のようになります。
CREATE TABLE item ( key MACADDR PRIMARY KEY, a0 VARCHAR, a1 VARCHAR, a2 VARCHAR )
だから、本当の問題は次のとおりです。更新/交換操作の速度をさらに上げるにはどうすればよいですか? (私はこれらの知見が「十分に良い」と思っていますが、私はSOの群衆をタップしないであきらめたくないと思っています:)
もう少しエレガントなreplace_item壊れていることが大歓迎です。
再現を試みる場合は、テストスクリプトはhereです。しかし、それを最初にチェックすることを忘れないでください...それはWorksForMeですが、...
dbを編集する必要があります。あなたの設定に合わせてconnect()行を追加してください。 freenodeの@ #postgresqlでアンドレスへ
EDIT
おかげで私は、単一のクエリ更新で別のテストを持っています。 (上記のupdate_andresとしてリストされている)複数行の挿入によく似ています。
UPDATE item
SET a0=i.a0, a1=i.a1, a2=i.a2
FROM (VALUES ('00:00:00:00:00:01', 'v0', 'v1', 'v2'),
('00:00:00:00:00:02', 'v3', 'v4', 'v5'),
...
) AS i(key, a0, a1, a2)
WHERE item.key=i.key::macaddr
EDIT私は、インサート・ツー・温度で別のテストを持っている以下のfreenodeのと水差し/ JWP @ #postgresqlでmerlin83に
感謝を/削除/挿入アプローチ(update_merlin83」として記載されている(I/d/i)」)。
INSERT INTO temp_item (key, a0, a1, a2)
VALUES (
('00:00:00:00:00:01', 'v0', 'v1', 'v2'),
('00:00:00:00:00:02', 'v3', 'v4', 'v5'),
...);
DELETE FROM item
USING temp_item
WHERE item.key=temp_item.key;
INSERT INTO item (key, a0, a1, a2)
SELECT key, a0, a1, a2
FROM temp_item;
私の直感では、これらのテストは、実際のシナリオでのパフォーマンスに非常に代表するものではないということですが、私は違いがさらなる調査のための最も有望なアプローチの指示を与えるのに十分素晴らしいと思います。 perftest.pyスクリプトには、チェックアウトしたい人のためのすべてのアップデートが含まれています。これは、しかし、かなり醜いですので、あなたのゴーグルを忘れないでください:) freenodeの@ #postgresqlで
アンドレスは、私のように記載されている、インサート・ツー・TEMP /更新バリアント(でテストする必要があることを指摘し
EDIT上記の「update_merlin83(i/u)」)。
INSERT INTO temp_item (key, a0, a1, a2)
VALUES (
('00:00:00:00:00:01', 'v0', 'v1', 'v2'),
('00:00:00:00:00:02', 'v3', 'v4', 'v5'),
...);
UPDATE item
SET a0=temp_item.a0, a1=temp_item.a1, a2=temp_item.a2
FROM temp_item
WHERE item.key=temp_item.key
EDIT
おそらく最終編集: 私はより良い私たちの負荷のシナリオに一致するように私のスクリプトを変更し、数字が少し物事をスケールアップし、いくつかのランダム性を追加する場合でも保持するようです。誰かが他のシナリオと非常に異なる数字を得たら、それについて知りたいと思うでしょう。
を助けるかもしれませんか?外国キー? –
テストスクリプトにはありません。現実世界では、1つです。 –
あなたの 'UPDATE'の' EXPLAIN ANALYZE'を投稿できますか?私はエスティメータが何を起こすべきかを知りたい。 – Sean