Un moyen de sélectionner sans provoquer de verrouillage dans MySQL?

126

Requete:

SELECT COUNT(online.account_id) cnt from online;

Mais la table en ligne est également modifiée par un événement, si souvent je peux voir le verrouillage en courant show processlist.

Y a-t-il une grammaire dans MySQL qui peut faire que l'instruction select ne provoque pas de verrous?

Et j'ai oublié de mentionner ci-dessus que c'est sur une base de données esclave MySQL.

Après avoir ajouté dans my.cnf:transaction-isolation = READ-UNCOMMITTED l'esclave rencontrera une erreur:

Erreur 'La journalisation binaire n'est pas possible. Message: Le niveau de transaction 'READ-UNCOMMITTED' dans InnoDB n'est pas sûr pour le mode binlog 'STATEMENT' 'sur requête

Alors, y a-t-il un moyen compatible de faire cela?

OMG
la source
3
Pour d'autres qui rencontrent cette question et ont du mal avec les verrous sur leurs tables: la manière dont mySQL utilise les verrous en interne dépend du moteur de stockage. Lisez la réponse de @zombat ci-dessous.
Simon Forsberg

Réponses:

169

Vous avez trouvé un article intitulé "MYSQL WITH NOLOCK"

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

dans MS SQL Server, vous procédez comme suit:

SELECT * FROM TABLE_NAME WITH (nolock)

et l'équivalent MYSQL est

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

ÉDITER

Michael Mior a suggéré ce qui suit (à partir des commentaires)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;
Jon Erickson
la source
54
Juste une note aux futurs lecteurs que vous voudrez peut-être éliminer SESSIONet ainsi faire appliquer le niveau de transaction uniquement à la prochaine transaction. Ensuite, remplacez simplement la troisième instruction ci-dessus par COMMIT. Ce sera un noop dans ce cas, mais cela aura pour effet secondaire de mettre fin à la transaction et de réinitialiser au niveau d'isolement par défaut.
Michael Mior le
3
Juste une note, ce lien est mort ... :(
longda
5
Désolé, mais je dois rejeter cette réponse pour ne pas mentionner les différences très importantes entre InnoDB et MyISAM ici. Comme indiqué par @omg ci-dessus, cela fonctionnera pour InnoDB mais pas pour les tables MyISAM.
Simon Forsberg
4
@Craig Il est certainement inexact que MyISAM n'émette pas de verrous READ pendant les requêtes SELECT - il y a des verrous et contrairement à InnoDB, ces verrous sont des verrous de table, bloquant tous les verrous WRITE demandés et toutes les requêtes ultérieures pendant l'exécution. La question originale semble cependant concerner InnoDB et les niveaux d'isolement sont également inexistants pour MyISAM - la documentation de l' SET TRANSACTIONinstruction déclare: "Cette instruction définit le niveau d'isolation des transactions, utilisé pour les opérations sur les tables InnoDB."
syneticon-dj
1
Point concédé. :-) J'essayais vraiment de me référer au comportement de verrouillage de MyISAM vs InnoDB. Ces solutions basées sur le niveau d'isolement ne s'appliquent pas à MyISAM, qui n'est pas transactionnel, il utilise donc un simple verrou de table. MyISAM UPDATE et DELETE doivent attendre que le verrou de la table soit effacé, de sorte que toute file d'attente de SELECT ultérieure derrière la demande d'écriture est bloquée jusqu'à la fin de l'écriture. MyISAM n'a pas de "lectures sales" et aucun moyen de permettre à la plupart des écritures de se produire en même temps que les lectures, donc inutile de se plaindre des commentaires ici "ne pas adresser MyISAM". Je pense que c'est ce à quoi je voulais en venir. :-)
Craig
24

Si la table est InnoDB, voir http://dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.html - il utilise consistent-read (mode sans verrouillage) pour les SELECT "qui font ne spécifiez pas FOR UPDATE ou LOCK IN SHARE MODE si l'option innodb_locks_unsafe_for_binlog est définie et que le niveau d'isolement de la transaction n'est pas défini sur SERIALIZABLE. Ainsi, aucun verrou n'est défini sur les lignes lues à partir de la table sélectionnée ".

Alex Martelli
la source
16

Utilisation

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

Les documents de la version 5.0 sont disponibles .

Les documents de la version 5.1 sont disponibles .

Pas moi
la source
2
Merci, je pense que c'est proche, mais combien de temps cette déclaration prendra-t-elle effet? Je vais utiliser cette instruction dans un programme PHP, et il vaut mieux réinitialiser le NIVEAU D'ISOLATION DES TRANSACTIONS automatiquement une fois la requête terminée
omg
14

Vous voudrez peut-être lire cette page du manuel MySQL. La façon dont une table est verrouillée dépend du type de table dont il s'agit.

MyISAM utilise des verrous de table pour atteindre une vitesse de lecture très élevée, mais si vous avez une instruction UPDATE en attente, alors les futurs SELECTS feront la queue derrière UPDATE.

Les tables InnoDB utilisent le verrouillage au niveau des lignes, et vous n'aurez pas la table entière verrouillée derrière une UPDATE. Il existe d'autres types de problèmes de verrouillage associés à InnoDB, mais vous trouverez peut-être que cela répond à vos besoins.

zombat
la source
1
"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED" fonctionnera-t-il pour les tables MyISAM?
omg
5
Les tables MyISAM ne prennent en charge les transactions sous aucune forme. Une requête transactionnelle s'exécutera sur une table MyISAM, donc la requête que vous mentionnez ci-dessus s'exécutera, mais elle n'aura aucun effet.
zombat
1
Alors, que puis-je faire pour éviter que SELECTS ne fasse la queue dans le cas de MyISAM?
omg
6
que puis-je faire pour éviter la file d'attente de SELECTS dans le cas de MyISAM? Passez à innodb. MyISAM utilise des verrous de niveau table pour chaque requête. C'est un défaut majeur.
Frank Farmer
2

Selon le type de votre table, le verrouillage fonctionnera différemment, mais il en sera de même pour un décompte SELECT. Pour les tables MyISAM, une simple table SELECT count (*) FROM ne doit pas verrouiller la table car elle accède aux métadonnées pour extraire le nombre d'enregistrements. Innodb prendra plus de temps car il doit saisir la table dans un instantané pour compter les enregistrements, mais cela ne devrait pas provoquer de verrouillage.

Vous devriez au moins avoir concourant_insert défini sur 1 (par défaut). Ensuite, s'il n'y a pas de "lacunes" dans le fichier de données à remplir pour la table, des insertions seront ajoutées au fichier et SELECT et INSERT peuvent se produire simultanément avec les tables MyISAM. Notez que la suppression d'un enregistrement met un «vide» dans le fichier de données qui tentera d'être rempli par les insertions et mises à jour futures.

Si vous supprimez rarement des enregistrements, vous pouvez définir concurrent_insert égal à 2 et les insertions seront toujours ajoutées à la fin du fichier de données. Ensuite, les sélections et les insertions peuvent se produire simultanément, mais votre fichier de données ne sera jamais plus petit, quel que soit le nombre d'enregistrements que vous supprimez (à l'exception de tous les enregistrements).

En fin de compte, si vous avez beaucoup de mises à jour, d'insertions et de sélections sur une table, vous devriez en faire InnoDB. Vous pouvez cependant mélanger librement les types de table dans un système.

Brent Baisley
la source
1

une autre façon d'activer la lecture sale dans mysql est d'ajouter un indice: LOCK IN SHARE MODE

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 
PuGong
la source
"Si autocommit est défini sur 1, les clauses LOCK IN SHARE MODE et FOR UPDATE n'ont aucun effet." ... et autocommit = 1 est la valeur par défaut
Martin Zvarík
0

De cette référence:

Si vous acquérez un verrou de table explicitement avec LOCK TABLES, vous pouvez demander un verrou READ LOCAL plutôt qu'un verrou READ pour permettre à d'autres sessions d'effectuer des insertions simultanées pendant que la table est verrouillée.

Paul Sonier
la source
0

Les SELECTs n'effectuent normalement aucun verrouillage qui vous tient à cœur sur les tables InnoDB. Le niveau d'isolation de transaction par défaut signifie que les sélections ne verrouillent pas les choses.

Bien sûr, la contestation se produit toujours.

MarkR
la source
1
Je sais que cet article est ancien, mais cette réponse est trop générale et n'est parfois vraie. Voir dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html . Serrures certainement sont acquis pour lit, selon le niveau d'isolement. Plus précisément, dans ce cas, l'affiche traite de bases de données répliquées et a déclaré explicitement qu'il peut utiliser show processlistpour voir réellement les verrous. Il est donc prudent de supposer que des verrous sont effectivement pris.
Craig
1
La réponse est toujours vraie. Il y a bien sûr des verrouillages - des mutex internes à l'intérieur d'innodb qui sont utilisés (mutex de pool de tampons innodb, par exemple). La plupart des utilisateurs ne se soucient pas ou ne remarquent pas ces verrous et ils ne se disputent normalement que pendant les opérations DDL (par exemple si vous avez un pool de mémoire tampon 16G et que vous faites "drop table" dans un autre thread). Mais cela ne prend aucun verrou de ligne par défaut. C'est ce que je voulais dire. La réponse était cependant assez vague.
MarkR
1
Toujours toujours? Que faire si le niveau d'isolement de transaction est défini sur sérialisable ou si l'instruction select utilise LOCK IN SHARE MODE et que l'autocommit est désactivé? Je sais que de nombreux serveurs de base de données (la plupart / tous?) Utilisent maintenant l'isolement de snapshot par défaut au lieu d'une véritable sérialisation, mais n'y a-t-il pas encore des justifications occasionnelles pour forcer les lectures sérialisables? Mais il semble que vous disiez que dans tous les cas normaux à distance, les conditions par défaut dans MySQL ne provoquent pas de verrous de lecture qui affectent d'autres threads, alors ne vous inquiétez pas d'un problème que vous n'avez pas? J'ai essayé d'annuler mon vote défavorable, BTW. Désolé ...
Craig
3
J'ai dit "pas normalement". Je voulais dire si vous faites une sélection normale (sans FOR UPDATE ou LOCK IN SHARE MODE) et utilisez le niveau d'isolation de transaction par défaut. Il existe des cas valables pour modifier le niveau d'isolement, mais je ne le ferais que par session, jamais par défaut.
MarkR