数百万行のテーブルがあり、5万行を更新するトランザクションを実行する場合、これによるパフォーマンスへの影響は何ですか?
正しくインデックスが付けられていると仮定すると、長くはかからないはずですが、どの行がロックされ、そのテーブルの使用にどのような影響がありますか?
私の質問はPostgres 9.3です。バリエーションがあると思います。
はい、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のドキュメントには、より高いトランザクションレベルを使用する場合のブロッキングとシリアル化の失敗を回避する方法に関する パフォーマンスの提案 も含まれています。
1はい
更新される行は読み取ることができ、トランザクションがコミットされるまで古い値が表示されます。
2はい
書き込まれていない行は影響を受けません。
3いいえまたははい。
他のトランザクションがデッドロックを必要とするロックを保持している場合は、デッドロックが明確になり、トランザクションの1つがキャンセルされます。その段階でエラーで終了するか、続行を許可されます。
このため、長期間存続するトランザクションは最小限に抑えるのが最善です。