Mysql
 sql >> Base de données >  >> RDS >> Mysql

Guide des nuls pour verrouiller innodb

Voici mes notes de travail avec le support MySQL sur un problème de verrouillage récent et étrange (version 5.1.37) :

Toutes les lignes et entrées d'index traversées pour accéder aux lignes en cours de modification seront verrouillées. C'est couvert à :

http://dev.mysql.com/doc /refman/5.1/en/innodb-locks-set.html

"Une lecture verrouillable, une mise à jour ou une suppression définit généralement des verrous d'enregistrement sur chaque enregistrement d'index analysé lors du traitement de l'instruction SQL. Peu importe qu'il y ait des conditions WHERE dans l'instruction qui excluraient la ligne. InnoDB fait ne se souvient pas de la condition WHERE exacte, mais ne sait que quelles plages d'index ont été analysées. ... Si vous n'avez aucun index adapté à votre instruction et que MySQL doit analyser la table entière pour traiter l'instruction, chaque ligne de la table devient verrouillée, ce qui en turn bloque toutes les insertions d'autres utilisateurs dans la table."

Il est. Une solution de contournement souvent utile consiste à :

UPDATE selon la table, définissez n'importe quoi sur quelque chose où la clé primaire se trouve (sélectionnez la clé primaire à partir de la table où les contraintes sont triées par clé primaire);

La sélection interne n'a pas besoin de prendre de verrous et la mise à jour aura alors moins de travail à faire pour la mise à jour. La clause order by garantit que la mise à jour est effectuée dans l'ordre de la clé primaire pour correspondre à l'ordre physique d'InnoDB, le moyen le plus rapide de le faire.

Lorsqu'un grand nombre de lignes sont impliquées, comme dans votre cas, il peut être préférable de stocker le résultat de la sélection dans une table temporaire avec une colonne d'indicateur ajoutée. Sélectionnez ensuite dans la table temporaire où l'indicateur n'est pas défini pour obtenir chaque lot. Exécutez les mises à jour avec une limite de 1000 ou 10000 et définissez l'indicateur pour le lot après la mise à jour. Les limites maintiendront la quantité de verrouillage à un niveau tolérable tandis que le travail sélectionné ne devra être effectué qu'une seule fois. Validez après chaque lot pour libérer les verrous.

Vous pouvez également accélérer ce travail en faisant une somme sélective d'une colonne non indexée avant de faire chaque lot de mises à jour. Cela chargera les pages de données dans le pool de mémoire tampon sans prendre de verrous. Ensuite, le verrouillage durera moins longtemps car il n'y aura pas de lecture de disque.

Ce n'est pas toujours pratique mais quand c'est le cas, cela peut être très utile. Si vous ne pouvez pas le faire par lots, vous pouvez au moins essayer d'abord la sélection pour précharger les données, si elles sont suffisamment petites pour tenir dans le pool de mémoire tampon.

Si possible, utilisez le mode d'isolation de transaction READ COMMITTED. Voir :

http://dev.mysql.com/doc/refman /5.1/fr/set-transaction.html

Pour obtenir ce verrouillage réduit, il faut utiliser la journalisation binaire basée sur les lignes (plutôt que la journalisation binaire basée sur les instructions par défaut).

Deux problèmes connus :

  1. Les sous-requêtes peuvent parfois être moins qu'idéalement optimisées. Dans ce cas, il s'agissait d'une sous-requête dépendante indésirable - la suggestion que j'ai faite d'utiliser une sous-requête s'est avérée inutile par rapport à l'alternative dans ce cas à cause de cela.

  2. Les suppressions et les mises à jour n'ont pas la même gamme de plans de requête que les instructions de sélection, il est donc parfois difficile de les optimiser correctement sans mesurer les résultats pour déterminer exactement ce qu'elles font.

Ces deux éléments s'améliorent progressivement. Ce bogue est un exemple où nous venons d'améliorer les optimisations disponibles pour une mise à jour, bien que les changements soient importants et qu'il soit toujours en cours de contrôle qualité pour s'assurer qu'il n'a pas d'effets indésirables majeurs :

http://bugs.mysql.com/bug.php?id=36569