3

READ COMMITTED のデフォルトの分離レベルで同時ユーザーが実行した場合、次のトランザクションで何が問題になる可能性がありますか?

BEGIN TRANSACTION

SELECT * FROM t WHERE pid = 10 and r between 40 and 60
-- ... this returns tid = 1, 3, 5
-- ... process returned data ...
DELETE FROM t WHERE tid in (1, 3, 5)
INSERT INTO t (tid, pid, r) VALUES (77, 10, 35)
INSERT INTO t (tid, pid, r) VALUES (78, 10, 37)
INSERT INTO t (tid, pid, r) VALUES (79, 10, 39)

COMMIT
4

4 に答える 4

3

デッドロックによる重大なパフォーマンスの問題が発生する可能性があります

SELECT はページの共有ロックを取得し、DELETE はそれらのロックを排他ロックにアップグレードしようとします。

別のユーザーが同じクエリを実行していた場合、別のユーザーと同時に同じページで共有ロックを取得する可能性があります。次に、排他ロックにアップグレードしようとすると、他のすべての共有ロックが解放されるまで待機します。もう一方も、すべての共有ロックが解放されるのを待ちます。どちらも共有ロックを持ち、もう一方がその共有ロックを解放するのを待って、それ自体が排他ロックを取得できるようにします。同じことをしようとして他のクエリが山積みになり、すぐにデッドロックが検出され始め、クエリがキャンセルされてロールバックされ始めます。クエリの頻度によっては、DB エンジンのデッドロック検出が、新しいクエリが入ってくるのと同じ速さでクエリを強制終了しない場合があります。つまり、どのクエリも成功しません。

最初から排他ロックを取得するように要求するには、select にヒントのようなものを追加する必要があります。または、select をトランザクションの外に移動し、他のステートメントの where 基準で同時実行競合検出を使用することもできます。

于 2010-04-05T21:17:08.693 に答える
1

全体が私には奇妙です。選択の目的は何ですか?それは何も達成しません。必要なレコードを選択するために削除を書き込みます。同時ユーザーの問題は、値をハードコードしたため、同じレコードを挿入しようとするため、tid または tid、pid コンボにおそらくある一意の制約に遭遇する可能性があることです。

正直なところ、ここで何を達成しようとしていますか? これは、複数回実行しようとしている 1 回限りの使用を目的としたアドホック クエリのように見えます。このようにハードコーディングすることは、ほとんどの場合、悪い考えです。

于 2010-04-05T21:15:10.063 に答える
0

SELECTにロックを使用しないため、全員が同じ結果を取得し、レコードtid 1、3、および5が表示されます。全員がこれらのレコードを処理し、全員がこれらのレコードを削除しようとします。そして、それは機能しません。削除操作はロックを設定します。これらのレコードをロックできるのは1つのトランザクションのみであり、他のすべてのトランザクションは最初のトランザクションのコミットを待機する必要があります。このトランザクションは新しいレコードを挿入してコミットし、他のすべてのトランザクションは何も削除せず(レコードが見つからない、問題ありません)、新しいレコードも挿入します。これらのレコードには同じデータがありますが、それは問題ですか?

SELECT ... FROM ... FOR UPDATE;処理したいレコードをロックしたい場合があります 。http://www.postgresql.org/docs/8.4/interactive/sql-select.html

于 2010-04-06T06:45:30.093 に答える
0

oracle と postgres のどちらを使用しているかについて言及する必要があります。また、ロックを明示的に指定し、デフォルトの動作に依存しないようにする必要があります。これらは、他のデータベースまたはデータベースのバージョンで変更される場合があります。

于 2010-04-05T21:13:13.413 に答える