L'impasse dans MySQL due à Insérer par plusieurs threads
J'ai une application multithread qui tente de INSERT
un enregistrement dans une table en plusieurs lots. Chaque thread de traitement d'un lot. À la fois, j'obtiens erreur de Blocage, à la suite de la trace.
La table, je suis en train d'essayer d'insérer un enregistrement dans est comme ceci:
RecordBase (Col1, Col2, Col3)
Col1
et Col2
ensemble la forme d'une clé primaire composite.
J'ai pensé que cela pouvait être dû à une index-enregistrement serrure, mais la trace montre clairement que les états qui bloquent les uns les autres n'ont pas de tous les enregistrements en double. Alors pourquoi est-il causer impasse?
------------------------ LATEST DETECTED DEADLOCK ------------------------
2015-09-09 17:13:22 2b70324de700
*** (1) TRANSACTION:
TRANSACTION 1787379600, ACTIVE 7 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 486 lock struct(s), heap size 63016, 13085 row lock(s), undo log entries 8713 MySQL thread id 537443, OS thread handle 0x2b703286c700, query id 578560605 127.0.0.1 192.168.1.195 demoreleaseroot update
INSERT INTO Record_Base VALUES
('da5fd95c-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fcf08-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fc4eb-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fbabe-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fb087-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5fa616-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f99bf-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f8f0f-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f5e2e-4d8e-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('da5f52e3-4d8e-11e5-9761-22000bd9028a','101e7d
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 26232190 page no 5961 n bits 160 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379600 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 29 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 65376566306364332d353039352d313165352d393736312d323230303062; asc e7ef0cd3-5095-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c3290f; asc ) ;; 4: len 4; hex 80000000; asc ;; ***
(2) TRANSACTION: TRANSACTION 1787379848, ACTIVE 1 sec inserting mysql tables in use 1, locked 1 1030 lock struct(s), heap size 112168, 5801 row lock(s), undo log entries 2639 MySQL thread id 537467, OS thread handle 0x2b70324de700, query id 578563042 127.0.0.1 192.168.1.195 demoreleaseroot update INSERT INTO Record_Base VALUES
('4849f98e-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849ebe5-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849c44c-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849add7-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4849a0ef-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48499430-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48498752-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('48496d2d-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4848731e-5094-11e5-9761-22000bd9028a','101e7dcd-4c81-11e5-9ca0-22000bd8028c','0'),
('4846784e-5094-11e5-9761-22000bd9028a','101e7d
*** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 26232190 page no 5961 n bits 152 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379848 lock_mode X locks gap before rec Record lock, heap no 29 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 65376566306364332d353039352d313165352d393736312d323230303062; asc e7ef0cd3-5095-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c3290f; asc ) ;; 4: len 4; hex 80000000; asc ;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 26232190 page no 14639 n bits 192 index `PRIMARY` of table `provalant101_mxradon`.`Record_Base` trx id 1787379848 lock_mode X locks gap before rec insert intention waiting Record lock, heap no 121 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 30; hex 38393531613333352d353039342d313165352d393736312d323230303062; asc 8951a335-5094-11e5-9761-22000b; (total 36 bytes); 1: len 30; hex 31303165376463642d346338312d313165352d396361302d323230303062; asc 101e7dcd-4c81-11e5-9ca0-22000b; (total 36 bytes); 2: len 6; hex 00006a893f90; asc j ? ;; 3: len 7; hex b40001a7c71c1c; asc ;; 4: len 4; hex 80000000; asc ;;
*** WE ROLL BACK TRANSACTION (2)
Les blocages se produisent lorsque plusieurs opérations tenir les demandes d'une serrure. Dans votre cas, vous avez plusieurs threads de frapper la même table afin qu'il s'attend à ce que le blocage se produit. Un blocage n'est pas de raison de s'inquiéter. InnoDB les détecte automatiquement et jette les erreurs. Pour nous, les développeurs qui utilisent MySQL, cela signifie que nous avons juste à répéter la requête en cas d'erreur. Dans certains pseudo-code, ce serait quelque chose comme
J'ai fait de même de faire ma demande de travail. Je voudrais juste savoir en détail ce qui est à l'origine de ce blocage.
Le blocage est causé par votre threads accèdent à la même table en même temps (l'accès simultané). Afin d'éviter d'écraser les données, MySQL permet un accès séquentiel à la table, pour écrire. Pour un thread ou processus afin d'être autorisé à écrire dans un tableau, il doit acquérir un verrou. Toutefois, lorsque deux threads se battent pour acquérir un verrou - ne sera jamais acquérir, ce qui les met dans une boucle infinie. Pour briser cette boucle, MySQL jette les erreurs et les appelle cela une "impasse". TL;DR: votre simultanées insérer à partir de plusieurs threads à une table est à l'origine des blocages. (c'est l'explication simplifiée)
Je ne pense pas que ce soit la bonne explication. Innodb a verrouillage de ligne et il n'y a rien comme l'accès séquentiel à moins que la ligne en cours d'accès est le même. Dans le cas de l'Insertion, de la dossiers sont de toute façon unique afin que les verrous de niveau ligne peuvent ne pas provoquer des blocages. J'ai fait un peu plus de recherches et découvert que ce article pour expliquer le problème parfaitement
Ok, si vous êtes bien avec une autre explication alors je ne vais pas cul. Lorsque vous écrivez, vous ne pouvez pas accéder à la table, pour écrire, en même temps que deux choses ne peuvent pas écrire à en même temps. Vous aussi vous ne pouvez pas verrouiller une ligne si il n'y a pas de ligne d'être verrouillé. Vous aussi vous ne pouvez pas calculer la auto_increment en toute sécurité, à moins que vous séquentiellement accès le compteur de placer un verrou, incrémentation, de la libération et de laisser le thread en attente d'accès. Cependant, depuis que vous avez trouvé l'explication alors je suppose que tout va bien 🙂
while(true) if(do_query()) break;
J'ai fait de même de faire ma demande de travail. Je voudrais juste savoir en détail ce qui est à l'origine de ce blocage.
Le blocage est causé par votre threads accèdent à la même table en même temps (l'accès simultané). Afin d'éviter d'écraser les données, MySQL permet un accès séquentiel à la table, pour écrire. Pour un thread ou processus afin d'être autorisé à écrire dans un tableau, il doit acquérir un verrou. Toutefois, lorsque deux threads se battent pour acquérir un verrou - ne sera jamais acquérir, ce qui les met dans une boucle infinie. Pour briser cette boucle, MySQL jette les erreurs et les appelle cela une "impasse". TL;DR: votre simultanées insérer à partir de plusieurs threads à une table est à l'origine des blocages. (c'est l'explication simplifiée)
Je ne pense pas que ce soit la bonne explication. Innodb a verrouillage de ligne et il n'y a rien comme l'accès séquentiel à moins que la ligne en cours d'accès est le même. Dans le cas de l'Insertion, de la dossiers sont de toute façon unique afin que les verrous de niveau ligne peuvent ne pas provoquer des blocages. J'ai fait un peu plus de recherches et découvert que ce article pour expliquer le problème parfaitement
Ok, si vous êtes bien avec une autre explication alors je ne vais pas cul. Lorsque vous écrivez, vous ne pouvez pas accéder à la table, pour écrire, en même temps que deux choses ne peuvent pas écrire à en même temps. Vous aussi vous ne pouvez pas verrouiller une ligne si il n'y a pas de ligne d'être verrouillé. Vous aussi vous ne pouvez pas calculer la auto_increment en toute sécurité, à moins que vous séquentiellement accès le compteur de placer un verrou, incrémentation, de la libération et de laisser le thread en attente d'accès. Cependant, depuis que vous avez trouvé l'explication alors je suppose que tout va bien 🙂
OriginalL'auteur Aashish | 2015-09-10
Vous devez vous connecter pour publier un commentaire.
Ce genre de blocages sont connus comme Écart des Serrures. J'ai trouvé ce post très utile.
En outre, vous pouvez lire plus au sujet de l'écart de verrouillage dans la Manuel Mysql
J'ai écrit cet article medium.com/@syl.fabre/... pour expliquer comment nous avons traité avec ce qu'il est dans mon entreprise
OriginalL'auteur Aashish
Blocage s'est passé beaucoup de choses dans ma demande au passé en raison de mysql mécanismes. Je l'ai résolu de deux façons. Tout d'abord, j'ai mis le lot de travaux affectant la même table en même fil et de les exécuter de façon séquentielle, la deuxième j'ai mis un bloc try-catch autour d'exécutions de requêtes pour attraper erreur de blocage et de le laisser essayer la même exécution de la requête 5+ les temps, y compris une fonction de veille entre la tente.
OriginalL'auteur ozy
J'ai eu ce même problème de pop-up à moi, @Aashish 's réponse me l'a expliqué, donc si vous voulez comprendre pourquoi cela a fonctionné pour moi vous avez besoin de lire sa réponse.
Le scénario que j'avais:
J'ai eu un Index UNIQUE sur les colonnes Date et idSomething (L'ordre est important, la Date a été le 1er et idSomething seconde)
J'ai eu une piscine de 12 fils de l'insertion de la même plage de dates (3 jours) pour chaque idSomething (Environ 1500 idSomethings).
Le correctif:
Modification de l'index UNIQUE sur la colonne idSomething (1er) et la Date (2e).
Ensuite, le processus au lieu de traiter " + " dans une manière ordonnée, j'ai ajouté une lecture aléatoire de l'ordre, de sorte qu'il serait moins probable que idSomething I et I+1, seraient mises en commun dans le même temps.
De cette façon, l'Écart Verrouille n'a pas de chevauchement de l'autre et les blocages disparaissent.
OriginalL'auteur Jimmy