blocage dans postgres sur une simple requête de mise à jour
Je travaille avec postgres 9.1 et prise en impasse exception en vertu de l'excessive exécution d'une simple méthode de mise à jour.
Selon les journaux que le blocage se produit en raison de l'exécution de deux des mises à jour identiques en même temps.
mise à jour publique.vm_action_info ensemble last_on_demand_task_id=$1, version=version+1
Comment deux identiques de simples mises à jour peut se bloquer les uns les autres ?
L'erreur que j'obtiens dans le journal
2013-08-18 11:00:24 IDT HINT: See server log for query details.
2013-08-18 11:00:24 IDT STATEMENT: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
2013-08-18 11:00:25 IDT ERROR: deadlock detected
2013-08-18 11:00:25 IDT DETAIL: Process 31533 waits for ShareLock on transaction 4228275; blocked by process 31530.
Process 31530 waits for ExclusiveLock on tuple (0,68) of relation 70337 of database 69205; blocked by process 31533.
Process 31533: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
Process 31530: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
2013-08-18 11:00:25 IDT HINT: See server log for query details.
2013-08-18 11:00:25 IDT STATEMENT: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
2013-08-18 11:00:25 IDT ERROR: deadlock detected
2013-08-18 11:00:25 IDT DETAIL: Process 31530 waits for ExclusiveLock on tuple (0,68) of relation 70337 of database 69205; blocked by process 31876.
Process 31876 waits for ShareLock on transaction 4228275; blocked by process 31530.
Process 31530: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
Process 31876: update public.vm_action_info set last_on_demand_task_id=$1, version=version+1 where id=$2
le schéma est:
CREATE TABLE vm_action_info(
id integer NOT NULL,
version integer NOT NULL DEFAULT 0,
vm_info_id integer NOT NULL,
last_exit_code integer,
bundle_action_id integer NOT NULL,
last_result_change_time numeric NOT NULL,
last_completed_vm_task_id integer,
last_on_demand_task_id bigint,
CONSTRAINT vm_action_info_pkey PRIMARY KEY (id ),
CONSTRAINT vm_action_info_bundle_action_id_fk FOREIGN KEY (bundle_action_id)
REFERENCES bundle_action (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT vm_discovery_info_fk FOREIGN KEY (vm_info_id)
REFERENCES vm_info (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE,
CONSTRAINT vm_task_last_on_demand_task_fk FOREIGN KEY (last_on_demand_task_id)
REFERENCES vm_task (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT vm_task_last_task_fk FOREIGN KEY (last_completed_vm_task_id)
REFERENCES vm_task (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (OIDS=FALSE);
ALTER TABLE vm_action_info
OWNER TO vadm;
-- Index: vm_action_info_vm_info_id_index
-- DROP INDEX vm_action_info_vm_info_id_index;
CREATE INDEX vm_action_info_vm_info_id_index
ON vm_action_info
USING btree (vm_info_id );
CREATE TABLE vm_task
(
id integer NOT NULL,
version integer NOT NULL DEFAULT 0,
vm_action_info_id integer NOT NULL,
creation_time numeric NOT NULL DEFAULT 0,
task_state text NOT NULL,
triggered_by text NOT NULL,
bundle_param_revision bigint NOT NULL DEFAULT 0,
execution_time bigint,
expiration_time bigint,
username text,
completion_time bigint,
completion_status text,
completion_error text,
CONSTRAINT vm_task_pkey PRIMARY KEY (id ),
CONSTRAINT vm_action_info_fk FOREIGN KEY (vm_action_info_id)
REFERENCES vm_action_info (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE CASCADE
)
WITH (
OIDS=FALSE
);
ALTER TABLE vm_task
OWNER TO vadm;
-- Index: vm_task_creation_time_index
-- DROP INDEX vm_task_creation_time_index ;
CREATE INDEX vm_task_creation_time_index
ON vm_task
USING btree
(creation_time );
source d'informationauteur moshe
Vous devez vous connecter pour publier un commentaire.
Ma conjecture est que la source du problème est une circulaire de référence de clé étrangère dans vos tables.
TABLEAU vm_action_info
==> CLÉ ÉTRANGÈRE (last_completed_vm_task_id) RÉFÉRENCES vm_task (id)
TABLEAU vm_task
==> CLÉ ÉTRANGÈRE (vm_action_info_id) RÉFÉRENCES vm_action_info (id)
L'opération se compose de deux étapes:
Lorsque deux transactions de mise à jour de la même enregistrement dans le
vm_action_info
table en même temps, cela permettra d'en finir avec une situation de blocage.Regarder simple cas de test:
Dans la séance 1, nous avons ajouter un enregistrement à vm_task que la référence à id=2 dans vm_action_info
En même temps dans la session 2 une autre transaction commence:
Puis la 1ère transaction effectue la mise à jour:
mais cette commande se bloque et est en attente d'un verrou.....
puis la 2ème session effectue la mise à jour ........
Blocage détecté !!!
C'est parce que les deux INSERTs en vm_task place un verrou partagé sur la ligne id=2 dans la vm_action_info table en raison de la référence de clé étrangère. Ensuite, la première mise à jour essaie de placer un verrou en écriture sur cette ligne et se bloque parce que la ligne est verrouillé par un autre (seconde) de la transaction. Ensuite, la deuxième mise à jour, essaie de verrouiller le même enregistrement dans le mode d'écriture, mais il est verrouillé en mode partagé par la première opération. Et cette cause un blocage.
Je pense que cela peut être évité si vous placer un verrou en écriture sur le disque vm_action_info, la totalité de la transaction est composé de 5 étapes:
Il peut être simplement que votre système a été très occupé. Vous dites que vous avez rencontré avec "excessive" l'exécution de la requête.
Ce qui semble être la situation est-ce:
Ainsi - nous avons ce qui semble être des quatre transactions toutes les mise à jour de cette ligne en même temps. Transaction 4228275 n'est pas validée ou annulée encore et tient les autres. Deux d'entre eux ont été en attente pour deadlock_timeout secondes, sinon, nous serions pas voir le délai d'attente. Timout expire, détecteur de blocage prend un coup d'oeil, voit un tas d'entrelacs de transactions et annule l'un d'eux. Peut ne pas être strictement une impasse, mais je ne suis pas sûr si le détecteur est assez intelligent pour comprendre ça.
Essayez l'une de:
Probablement #3 est le plus simple 🙂 Peut être utile de définir log_lock_waits trop de sorte que vous pouvez voir si votre système est en vertu de ce genre de souche.