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!