web-dev-qa-db-ja.com

大規模トランザクションのパフォーマンスと同時実行性?

数百万行のテーブルがあり、5万行を更新するトランザクションを実行する場合、これによるパフォーマンスへの影響は何ですか?

正しくインデックスが付けられていると仮定すると、長くはかからないはずですが、どの行がロックされ、そのテーブルの使用にどのような影響がありますか?

  1. トランザクション中に更新される行は、トランザクションの開始後、終了前に読み取ることができますか?
  2. トランザクション中に更新されていない行は、トランザクションの開始後、終了前に読み取ることができますか?
  3. 別のトランザクションが、前に完了していないトランザクションによって変更されている行を変更しようとし始めた場合、そのトランザクションは開始時またはコミットを試みた後に失敗しますか(競合を想定)?

私の質問はPostgres 9.3です。バリエーションがあると思います。

3
NONONO

トランザクション中に更新される行は、トランザクションの開始後、終了前に読み取ることができますか?

はい、Postgresでは、読み取りは書き込みをブロックせず、書き込みは読み取りをブロックしません。 Postgresドキュメント は次のように述べています:

内部的には、マルチバージョンモデル(Multiversion Concurrency Control、MVCC)を使用してデータの整合性が維持されます。つまり、データベースのクエリを実行している間、各トランザクションは、基になるデータの現在の状態に関係なく、以前のデータ(データベースバージョン)のスナップショットを参照します。 […]ロックではなく同時実行制御のMVCCモデルを使用する主な利点は、データのクエリ(読み取り)のために取得されたロックが、データの書き込みのために取得されたロックと競合しないことです。 。

トランザクション中に更新されていない行は、トランザクションの開始後、終了前に読み取ることができますか?

はい。

別のトランザクションが、以前に完了していないトランザクションによって変更されている行を変更しようとし始めた場合、そのトランザクションは開始時またはコミットを試みた後に失敗しますか(競合を想定)?

これは トランザクション分離レベル と、読み取りまたはブラインド書き込みに依存する書き込みを発行するかどうかに依存します。デフォルトレベルRead Committedを使用すると、2番目のトランザクションは、最初のトランザクションが書き込みを完了するまで待機する必要があります。より高いトランザクションレベルでは、トランザクションの1つがシリアル化エラーで中止される可能性があります。

実際にこれを試すには、2つのpsqlセッションを実行します。

セッション1:

-- first set up a table
CREATE TABLE tools (id SERIAL PRIMARY KEY, description STRING);
INSERT INTO tools(description) VALUES('scredriver');
INSERT INTO tools(description) VALUES('hammer');

-- now type the following into two psql sessions
          SESSION 1             |          SESSION 2
                                |
BEGIN TRANSACTION;              |
UPDATE tools                    |
   SET description = 'anvil'    |
 WHERE id = 1;                  |
                                | BEGIN TRANSACTION;
                                |UPDATE tools
                                |   SET description = 'wrench'
                                | WHERE id = 1;
                                |-- this transaction is blocked
                                |-- until the other transaction
COMMIT TRANSACTION;             |-- commits

ご覧のとおり、セッション2はセッション1によってブロックされます。セッション1がコミットされた場合のみ、セッション2は続行できます。

Postgresのドキュメントには、より高いトランザクションレベルを使用する場合のブロッキングとシリアル化の失敗を回避する方法に関する パフォーマンスの提案 も含まれています。

3
taffer

1はい

更新される行は読み取ることができ、トランザクションがコミットされるまで古い値が表示されます。

2はい

書き込まれていない行は影響を受けません。

3いいえまたははい。

他のトランザクションがデッドロックを必要とするロックを保持している場合は、デッドロックが明確になり、トランザクションの1つがキャンセルされます。その段階でエラーで終了するか、続行を許可されます。

このため、長期間存続するトランザクションは最小限に抑えるのが最善です。

2
Jasen