web-dev-qa-db-fra.com

Une opération INSERT peut-elle aboutir à un blocage?

En supposant:

  • J'utilise l'isolation de transaction REPEATABLE_READ ou SERIALIZABLE (les verrous sont conservés chaque fois que j'accède à une ligne)
  • Nous parlons de plusieurs threads accédant à plusieurs tables simultanément.

J'ai les questions suivantes:

  1. Est-il possible qu'une opération INSERT provoque un blocage? Si oui, veuillez fournir un scénario détaillé montrant comment un blocage peut survenir (par exemple, le fil 1 fait ceci, le fil 2 fait cela, ..., un point mort).
  2. Pour les points bonus: répondez à la même question pour toutes les autres opérations (par exemple, SELECT, UPDATE, DELETE).

UPDATE: 3. Pour les points super bonus: comment puis-je éviter une impasse dans le scénario suivant?

Tableaux donnés:

  • permissions[id BIGINT PRIMARY KEY]
  • companies[id BIGINT PRIMARY KEY, name VARCHAR(30), permission_id BIGINT NOT NULL, FOREIGN KEY (permission_id) REFERENCES permissions(id))

Je crée une nouvelle société comme suit:

  • INSERT INTO autorisations; - insère permissions.id = 100
  • INSERT INTO companies (nom, permission_id) VALUES ('Nintendo', 100); - Inserts companies.id = 200

Je supprime une entreprise comme suit:

  • SELECT permission_id FROM entreprises WHERE id = 200; - retourne permission_id = 100
  • SUPPRIMER DES ENTREPRISES O ID = 200;
  • DELETE FROM permissions WHERE id = 100;

Dans l'exemple ci-dessus, l'ordre de verrouillage INSERT est [autorisations, sociétés], tandis que l'ordre de verrouillage SUPPRIMER est [sociétés, autorisations]. Existe-t-il un moyen de corriger cet exemple pour l'isolement REPEATABLE_READ ou SERIALIZABLE?

21
Gili

En règle générale, toutes les modifications peuvent provoquer un blocage et la sélection ne le fera pas (y revenir plus tard). Alors

  1. Non, vous ne pouvez pas les ignorer.
  2. Vous pouvez ignorer quelque peu la sélection en fonction de votre base de données et de vos paramètres, mais les autres vous donneront des impasses.

Vous n'avez même pas besoin de plusieurs tables.

La meilleure façon de créer une impasse est de faire la même chose dans un ordre différent.

Exemples SQL Server:

create table A
(
    PK int primary key
)

Session 1:

begin transaction
insert into A values(1)

Session 2:

begin transaction    
insert into A values(7)

Session 1:

delete from A where PK=7

Session 2:

delete from A where PK=1

Vous obtiendrez une impasse. Donc, cela prouvé inserts et supprime peut impasse.

Les mises à jour sont similaires:

Session 1:

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

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

Session 2:

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

Session 1:

update A set pk=9 where pk=2

Impasse!

SELECT ne doit jamais se bloquer, mais sur certaines bases de données, cela se produira, car les verrous utilisés interfèrent avec des lectures cohérentes. C'est juste la conception de moteur de base de données merdique cependant. 

SQL Server ne sera pas verrouillé sur un SELECT si vous utilisez SNAPSHOT ISOLATION. Oracle et moi-même pensons que Postgres ne se verrouillera jamais sur SELECT (sauf si vous avez FOR UPDATE qui réserve clairement une mise à jour de toute façon).

Donc, fondamentalement, je pense que vous avez quelques hypothèses incorrectes. Je pense avoir prouvé:

  1. Les mises à jour peuvent provoquer des blocages
  2. Les suppressions peuvent provoquer des blocages
  3. Les inserts peuvent provoquer des blocages
  4. Vous n'avez pas besoin de plus d'une table
  5. Vous avez besoin de plus d'une session

Vous devrez juste prendre mon mot sur SELECT;) mais cela dépendra de votre base de données et de vos paramètres.

28
LoztInSpace

En plus de la réponse de LoztInSpace, inserts peut provoquer des blocages même sans présence de deletes ou updates Tout ce dont vous avez besoin est un index unique et un ordre d'opérations inversé.

Exemple dans 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 !
5
Grisha Weintraub

Supposons que vous avez deux relations A et B et deux utilisateurs X et Y. La table A est WRITE verrouillée par l'utilisateur X et la table B est WRITE verrouillée par Y. La requête suivante vous donnera un verrou mort s'il est utilisé à la fois par les utilisateurs X et Y.

Select * from A,B

Il est donc clair qu'une opération Select peut provoquer un blocage, si des opérations de jointure impliquant plusieurs tables en font partie. Les opérations d'insertion et de suppression impliquent généralement des relations uniques. Donc, ils ne peuvent pas provoquer une impasse.

0
Deepu