ProblĂšme de verrou?
28 August 2007 par pĂ©bĂ©J’ai eu un petit problĂšme sympa Ă rĂ©soudre. En rĂ©sumĂ©, nous avons 2 tables t1 et t2.
mysql> select * from t1;
+——+——+
| id | name |
+——+——+
| 1 | a |
| 2 | b |
| 3 | ab |
| 4 | bc |
+——+——+
mysql> select * from t2;
+————–+———+
| dependent_id | base_id |
+————–+———+
| 1 | 1 |
| 3 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 3 | 2 |
| 4 | 2 |
+————–+———+
Nous ouvrons une transaction (T1) et nous exĂ©cutons la requĂȘte suivante.
SELECT * FROM t1 JOIN t2 WHERE t1.id=t2.dependent_id AND t2.base_id=1 FOR UPDATE;
+——+——+————–+———+
| id | name | dependent_id | base_id |
+——+——+————–+———+
| 1 | a | 1 | 1 |
| 3 | ab | 3 | 1 |
+——+——+————–+———+
Nous ouvrons une transaction (T2) et nous exĂ©cutons la requĂȘte suivante.
SELECT * FROM roles WHERE id=2 FOR UPDATE;
Et alors que les 2 requĂȘtes ne sont pas sensĂ©es travailler sur les mĂȘme lignes, T2 attend la fin de T1? Comment est ce possible?
Pour comprendre vous devez analyser le plan d’exĂ©cution.
mysql> explain SELECT * FROM t1 JOIN t2 WHERE t1.id=t2.dependent_id AND t2.base_id=1 FOR UPDATE;
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 7 | Using where |
| 1 | SIMPLE | t1 | ALL | PRIMARY | NULL | NULL | NULL | 3 | Using where |
Voila l’erreur, MySQL fait un full table scan (type ALL) pour exĂ©cuter cette requĂȘte et ainsi bloque toutes les lignes. T2 est ainsi obliger d’attendre la fin de T1. Pourquoi?
Ayant seulement 4 entrĂ©es dans cette table, l’optimiseur de MySQL prĂ©fĂšre un faire un full table scan plutot qu’utiliser un index. De la j’ ai insĂ©rĂ© d’autre entrĂ©e dans la table t1, et le plan d’exĂ©cution a changĂ©.
| 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 217 | Using where |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 4 | t2.dependent_id | 1 | |
MySQL bloque ainsi seulement la PK et fait bien du ‘row level locking’. T2 peut aboutir sans problĂšme. CQFD!
Autres billets susceptibles de vous intéresser :

5 September 2007 at 10:26 am
Comme je sais que tout change entre chaque version de MySQL, peut on savoir sur quelle version cette démonstration est valable ?
5 September 2007 at 10:35 am
Salut Greg,
je l’ai testĂ© sur la version utilisĂ© par la personne en question, soit MySQL 4.1.
NĂ©anmoins, je ne pense pas que MySQL ai modifiĂ© le fonctionnement de l’optimiser. Si la table est petite, il va toujours avoir tendance Ă faire un FULL TABLE scan que de s’embĂȘter avec des index.
5 September 2007 at 11:13 am
TestĂ© avec succĂšs sur postgrsql 8.1 quelque soit le nombre d’enregistrements,
ils ont par contre un autre bug (extrait de la doc):
BEGIN;
SELECT * FROM mytable WHERE key = 1 FOR UPDATE;
SAVEPOINT s;
UPDATE mytable SET … WHERE key = 1;
ROLLBACK TO s;
Le «rollback to s» va quand mĂȘme unlocker les rows de la table du prĂ©cĂ©dent SELECT.