web-dev-qa-db-ja.com

INSERT操作でデッドロックが発生する可能性はありますか?

仮定:

  • REPEATABLE_READまたはSERIALIZABLEトランザクション分離を使用しています(行にアクセスするたびにロックが保持されます)
  • 複数のテーブルに同時にアクセスする複数のスレッドについて話している。

次の質問があります。

  1. INSERT操作でデッドロックが発生する可能性はありますか?その場合、デッドロックが発生する方法を示す詳細なシナリオを提供してください(たとえば、スレッド1がこれを実行し、スレッド2がそれを実行します) ...、デッドロック)。
  2. ボーナスポイントの場合:他のすべての操作(SELECT、UPDATE、DELETEなど)について同じ質問に答えます。

[〜#〜] update [〜#〜]:3.スーパーボーナスポイントの場合:次のシナリオでデッドロックを回避するにはどうすればよいですか?

与えられたテーブル:

  • アクセス許可_[id BIGINT PRIMARY KEY]_
  • companies[id BIGINT PRIMARY KEY, name VARCHAR(30), permission_id BIGINT NOT NULL, FOREIGN KEY (permission_id) REFERENCES permissions(id))

次のように新しい会社を作成します。

  • INSERT INTO権限。 -permissions.id = 100を挿入します
  • INSERT INTO companies(name、permission_id)VALUES( 'Nintendo'、100); -companies.id = 200を挿入します

会社を次のように削除します。

  • SELECT permission_id FROM FROM WHERE WHERE id = 200; -permission_id = 100を返します
  • 会社から削除WHERE id = 200;
  • 権限から削除WHERE id = 100;

上記の例では、INSERTロック順序は[許可、会社]ですが、DELETEロック順序は[会社、許可]です。 _REPEATABLE_READ_またはSERIALIZABLE分離のこの例を修正する方法はありますか?

22
Gili

一般に、すべての変更はデッドロックを引き起こす可能性があり、selectはそれを引き起こしません(後で取得します)。そう

  1. これらを無視することはできません。
  2. データベースや設定によっては、selectをいくらか無視することができますが、それ以外ではデッドロックが発生します。

複数のテーブルは必要ありません。

デッドロックを作成する最良の方法は、同じことを異なる順序で行うことです。

SQL Serverの例:

create table A
(
    PK int primary key
)

セッション1:

begin transaction
insert into A values(1)

セッション2:

begin transaction    
insert into A values(7)

セッション1:

delete from A where PK=7

セッション2:

delete from A where PK=1

デッドロックが発生します。そのため、挿入と削除がデッドロックになる可能性があります。

更新は似ています:

セッション1:

begin transaction    
insert into A values(1)
insert into A values(2)
commit

begin transaction
update A set PK=7 where PK=1

セッション2:

begin transaction
update A set pk=9 where pk=2    
update A set pk=8 where pk=1

セッション1:

update A set pk=9 where pk=2

デッドロック!

SELECTはデッドロックを起こすべきではありませんが、データベースによっては、使用するロックが一貫した読み取りを妨害するため、デッドロックが発生します。ただし、これはデータベースエンジンの設計がひどいものです。

SNAPSHOT ISOLATIONを使用する場合、SQL ServerはSELECTをロックしません。 Oracleと私はPostgresがSELECTをロックしないと思います(とにかく更新のために予約されているFOR UPDATEがない限り)。

だから基本的に私はあなたがいくつかの誤った仮定を持っていると思います。私は証明したと思います:

  1. 更新によりデッドロックが発生する可能性がある
  2. 削除するとデッドロックが発生する可能性がある
  3. 挿入はデッドロックを引き起こす可能性があります
  4. 複数のテーブルは必要ありません
  5. あなたdo複数のセッションが必要

SELECTで私のWordを使用する必要があります;)しかし、それはDBと設定に依存します。

29
LoztInSpace

LoztInSpaceの回答に加えて、insertsdeletesまたはupdatesが存在しなくてもデッドロックを引き起こす可能性があります。必要なのは、一意のインデックスと逆の操作順序だけです。

Oracleでの例:

create table t1 (id number);
create unique index t1_pk on t1 (id);

--thread 1 :
insert into t1 values(1);
--thread 2
insert into t1 values(2);
--thread 1 :
insert into t1 values(2);
--thread 2
insert into t1 values(1);  -- deadlock !
6

2つのリレーションABがあり、2人のユーザーXYがあるとします。テーブルAはユーザーXによって書き込みロックされ、テーブルBはYによって書き込みロックされます。次に、ユーザーXとユーザーYの両方が使用すると、次のクエリはデッドロックを生成します。

Select * from A,B

したがって、複数のテーブルを含む結合操作がその一部である場合、Select操作はデッドロックを引き起こす可能性があります。通常、挿入および削除操作には単一の関係が含まれます。したがって、デッドロックが発生することはありません。

0
Deepu