3

主キーのリストがあり、行ごとに 1 つの値を更新する必要があるとします。実行する方が良いですか:

-- run 10,000 of these queries
UPDATE mytable SET myflag = 1 WHERE id = [each_id]

または、次のように更新をバッチ クエリに結合します。

-- run 100 of these queries, where the IN () list contains about 100 elements
UPDATE mytable SET myflag = 1 WHERE id IN (3, 4, 5, 9, 99, ... 7887 )

100 個の IN () アイテムを含む 100 個のクエリはどうでしょうか?

4

5 に答える 5

5

ない。PostgreSQLでは、代わりに次のようにします。

WITH x AS (
   SELECT unnest('{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
                 ,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
                 ,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60
                 ,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80
                 ,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100
                 }'::int[]) AS id
   )
UPDATE mytable t
SET    myflag = 1
FROM   x
WHERE  t.id = x.id;

10000 個の ID が多いという視覚的な手がかりを与えるために、例に非常に多くの ID を入れました。質問で提示された 2 つのアイデアは、次のいずれかになります。

  1. リストを解析し、10000 個のステートメントをまとめてサーバーに送信する必要があります。これには、UPDATE 自体よりも時間がかかる可能性があります。

  2. 一致する ID を求めて、id各個人の 10000 項目のリスト (配列) を検索する必要があります。mytable標準インデックスは使用できません。これは非常に遅くなります。のサイズでパフォーマンスが低下しmytableます。

上のインデックスmytable.idは、両方のバリアントを桁違いに上回るために提示されたすべての代替ニーズです。

CTEは配列を 1 回解析します(サブクエリも機能します - MySQL には CTE がありません) unnest()。1 つのステートメントですべてを実行すると、10000 ステートメントよりも桁違いに優れています。これらのステートメントが個々のトランザクションで実行される場合は、さらに桁違いに追加します。個別のセッションを使用する必要がある場合は、別のセッションを追加してください。

書き込み負荷が高い場合にロックの問題が発生するデータベースには、まれな例外が適用されます。アドバイスされているようにベンチマークするだけです。EXPLAIN ANALYZEは PostgreSQL の友達です。

操作が巨大になり、ほとんどのテーブルが更新された場合、および/またはディスク容量または RAM が不足している場合でも、操作をいくつかの論理チャンクに分割することをお勧めします。スポット。ほとんどの場合、HOT 更新UPDATEで以前の実行からのテーブルの肥大化をリサイクルできるようにします。この関連する質問を検討してください。

于 2012-06-29T18:36:09.013 に答える
4

非常に大きなデータ セットの挿入を行う場合、2 番目の方法の方が桁違いに高速であることがわかりました。これはシステムに大きく依存しますが、クエリの IN 部分は、テーブルのサイズやインデックスなどに応じて多かれ少なかれ効率的になります。

独自の簡単なベンチマークを実行することが、唯一の方法です。

于 2012-06-29T17:01:40.563 に答える
3

通常、 1 つのupdate ステートメントを実行するのが最も効率的です。例えば、

UPDATE mytable set myflag=1 where id IN (select id from someothertable where stuff). 

スキーマによっては遅くなる可能性があります。ベンチマークして調べる必要があります。

クライアントからデータベース サーバーに対して 10,000 ステートメントを実行すると、ほぼ確実に遅くなることに注意してください。ストアド プロシージャで 10,000 件の更新を実行することと、クライアントから 10,000 件の更新を実行することは、2 つのまったく異なることです。10,000 回の更新を実行する場合は、必ず SP で実行してください。

于 2012-06-29T17:01:03.507 に答える
2

通常、RDBMS ラウンドトリップが支配的な要因ですが、この場合、inリストを解析するためのコストも高くなる可能性があります。ただし、クエリをパラメーター化する場合は、解析が 1 回だけ行われるため、2 番目のソリューションの方が高速になる可能性が非常に高くなります。

于 2012-06-29T17:00:03.830 に答える
0

これは主に、ハードディスクへの fsync の量に依存します。これは、システムで最も遅い部分です。

PostgreSQL の場合: 少量のトランザクションで、可能であれば 1 つのトランザクションで実行します。ただし、行のロックに注意してください。2 つのトランザクションが同じ行を同時に更新することはできません。

于 2012-06-29T16:59:56.967 に答える