mardi 9 décembre 2008

Utilisation de LAST_INSERT_ID()

La fonction MySQL LAST_INSERT_ID() permet de récupérer la valeur du dernier incrément généré lors de l'insertion de données dans une table contenant une colonne auto_increment.
Il peut être utile de récupérer cette valeur pour la réinjecter dans une seconde table. J'ai par exemple sur mon serveur les 2 tables suivantes :

mysql [localhost] {msandbox} (test) > select * from t1;
+----+------+
| id | name |
+----+------+
| 1 | c |
| 2 | c2 |
| 3 | c3 |
+----+------+
3 rows in set (0.00 sec)

mysql [localhost] {msandbox} (test) > select * from t2;
+------+------------+
| id | dt |
+------+------------+
| 2 | 2008-12-09 |
+------+------------+
1 row in set (0.00 sec)

Ayant eu l'occasion de vérifier le code de certains développeurs j'ai repéré du code utilisant cette fonction mais faisant appel à la table en question sans pour autant que cela soit nécessaire pour le résultat. Je me suis alors posé la question suivante : Y a t il un impact à faire appel à la table sans que cela soit nécessaire ?
Si on regarde les 2 plans d'exécution cela donne :

mysql [localhost] {msandbox} (test) > explain select last_insert_id();
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)

mysql [localhost] {msandbox} (test) > explain select last_insert_id() from t2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 1 | |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)


L'appel à la table semble avoir besoin d'accéder à une ligne. Cela semble louche...

Vous l'aurez compris il faut bien sûr bencher pour savoir s'il y a une grosse différence. Pour cela MySQL met à disposition la fonction BENCHMARK() qui n'est pas très connue :

mysql [localhost] {msandbox} (test) > insert into t1(name) values('c4');
Query OK, 1 row affected (0.01 sec)

mysql [localhost] {msandbox} (test) > SELECT BENCHMARK(1000000,(SELECT last_insert_id() from t2));
+------------------------------------------------------+
| BENCHMARK(1000000,(SELECT last_insert_id() from t2)) |
+------------------------------------------------------+
| 0 |
+------------------------------------------------------+
1 row in set (5.09 sec)

mysql [localhost] {msandbox} (test) > SELECT BENCHMARK(1000000,(SELECT last_insert_id()));
+----------------------------------------------+
| BENCHMARK(1000000,(SELECT last_insert_id())) |
+----------------------------------------------+
| 0 |
+----------------------------------------------+
1 row in set (0.03 sec)


Voilà donc notre réponse. Accéder à la table, chose inutile pour notre résultat, prend plus de temps.

2 commentaires:

Camille Huot a dit…

ça ne vaut pas une bonne petite séquence si tu veux mon avis ! :)

Cyril Scetbon a dit…

On est pas dans la même catégorie :)