vendredi 25 septembre 2026

À propos

Contact

Extensions

dbDelta à chaque admin_init : l’anti-pattern qui ralentit le back-office

Un audit de performance révèle qu'une extension recalcule et compare son schéma de base à chaque chargement de l'administration, sur des dizaines de milliers de sites.

Par Clément Hadrot • 18 juillet 2022 • 3 min de lecture • Aucun commentaire
dbDelta à chaque admin_init : l'anti-pattern qui ralentit le back-office

Ce qu’on voit régulièrement en audit de performance, chez des clients qui se plaignent d’un back-office WordPress plus lent qu’il ne devrait l’être : une extension, généralement bien intentionnée dans son intention initiale, qui accroche l’appel à dbDelta() directement sur le hook admin_init, sans aucune condition. Résultat : à chaque chargement d’une page d’administration, par n’importe quel utilisateur connecté, WordPress relit la structure de la table concernée en base, la compare à la structure attendue déclarée dans le code, et exécute les requêtes de correction nécessaires, même quand strictement rien n’a changé depuis la dernière fois.

Pourquoi ça coûte cher

La fonction dbDelta(), fournie par le cœur de WordPress via le fichier wp-admin/includes/upgrade.php, est conçue pour comparer une définition de table SQL fournie en argument à la structure réellement présente en base, colonne par colonne, index par index, puis pour générer et exécuter uniquement les requêtes ALTER TABLE nécessaires pour aligner les deux. Ce travail de comparaison, même quand il ne débouche sur aucune modification effective, implique plusieurs requêtes SHOW COLUMNS et SHOW INDEX vers le serveur MySQL, avec un traitement PHP non négligeable pour parser et comparer les résultats.

Sur les sites audités, ce traitement complet, exécuté inutilement à chaque chargement admin, ajoutait entre 40 et 80 millisecondes à chaque requête, un temps qui semble anodin pris isolément mais qui, multiplié par des dizaines de chargements de page dans une session d’administration classique, se traduit par une sensation de lenteur perceptible et cumulée pour l’équipe éditoriale du client.

Le code fautif

L'essentiel à retenir : dbDelta n'est pas conçu pour être appelé à chaque requête admin ; Une comparaison de schéma coûte du temps même quand rien n'a changé ; Une vérification de version suffit à ne déclencher dbDelta qu'une seule fois
add_action( 'admin_init', function() {
    global $wpdb;

    $sql = "CREATE TABLE {$wpdb->prefix}stats_visites (
        id BIGINT UNSIGNED AUTO_INCREMENT,
        article_id BIGINT UNSIGNED NOT NULL,
        date_visite DATETIME NOT NULL,
        PRIMARY KEY (id)
    ) {$wpdb->get_charset_collate()};";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta( $sql );
} );

Ce code, pris isolément, n’est pas incorrect du point de vue du résultat produit : la table finit toujours correctement structurée. Le problème n’est pas dans ce que fait dbDelta(), mais dans la fréquence à laquelle on la sollicite pour un travail qui, par nature, n’a besoin d’être fait qu’une seule fois par changement réel de structure, c’est-à-dire à chaque nouvelle version de l’extension qui modifie effectivement son schéma.

Le correctif : versionner le schéma

La bonne pratique, largement documentée mais souvent oubliée sous la pression d’un développement rapide, consiste à comparer une version de schéma stockée en option à une constante de version déclarée dans le code, et à ne déclencher dbDelta() que lorsque ces deux valeurs diffèrent :

define( 'STATS_VISITES_DB_VERSION', '1.2' );

add_action( 'plugins_loaded', function() {
    $version_installee = get_option( 'stats_visites_db_version', '0' );

    if ( version_compare( $version_installee, STATS_VISITES_DB_VERSION, '<' ) ) {
        mettre_a_jour_table_stats_visites();
        update_option( 'stats_visites_db_version', STATS_VISITES_DB_VERSION );
    }
} );

function mettre_a_jour_table_stats_visites() {
    global $wpdb;

    $sql = "CREATE TABLE {$wpdb->prefix}stats_visites (
        id BIGINT UNSIGNED AUTO_INCREMENT,
        article_id BIGINT UNSIGNED NOT NULL,
        date_visite DATETIME NOT NULL,
        PRIMARY KEY (id)
    ) {$wpdb->get_charset_collate()};";

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta( $sql );
}

Avec cette approche, dbDelta() ne s’exécute plus qu’une seule fois, exactement au moment où le numéro de version stocké en base diverge de celui déclaré dans le code, typiquement juste après une mise à jour de l’extension. Sur des milliers de chargements admin suivants, la vérification se réduit à un simple get_option(), une opération quasi instantanée et souvent déjà servie par le cache d’objet si l’option est fréquemment lue.

Autres formes du même anti-pattern rencontrées en audit

  • Un appel à dbDelta() placé directement dans le corps principal d’un fichier de plugin, sans hook du tout, ce qui l’exécute à chaque chargement de n’importe quelle page, admin ou front, dès que le plugin est actif.
  • Une vérification de version qui compare une constante de version du plugin lui-même, censée refléter la version de l’extension entière, plutôt qu’une constante dédiée à la version du schéma de base, ce qui déclenche une comparaison de schéma à chaque changement de version du plugin même quand la structure de la table n’a pas bougé d’un octet.
  • L’absence totale de require_once vers le fichier contenant dbDelta(), compensée par un chargement systématique de tout wp-admin/includes/upgrade.php à chaque requête admin, ce qui charge inutilement du code non nécessaire en dehors des rares moments de mise à jour réelle.

Une fonction conçue pour un usage occasionnel de mise à jour de schéma ne devient pas gratuite simplement parce qu’elle est idempotente.

Prévention à l’échelle d’une équipe

Sur ce type de dette technique, la meilleure prévention reste une revue de code systématique qui vérifie, pour tout nouvel appel à dbDelta(), la présence d’un mécanisme de version associé. Un simple outil comme Query Monitor, activé en environnement de développement, permet aussi de repérer facilement les requêtes SHOW COLUMNS répétées à chaque chargement admin, symptôme immédiat de ce problème.

Notre verdict

dbDelta reste un outil précieux et bien conçu pour gérer l’évolution d’un schéma de base de données au fil des versions d’une extension. Le problème n’est jamais l’outil lui-même, mais la fréquence à laquelle on l’invoque sans discernement. Un simple mécanisme de version en option, comparé à une constante du code, suffit à transformer un anti-pattern coûteux en un traitement occasionnel et négligeable.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi