Chez Codeable, j’ai travaillé sur l’optimisation d’un site e-commerce propulsé par WooCommerce récemment, qui connaissait quelques problèmes de lenteur.
Sous phpMyAdmin, on trouvait également cette erreur:
Current selection does not contain a unique column
Si vous obtenez cette erreur, c’est que la structure de la table wp_options
n’est pas à jour donc nous la vérifions avec wp-cli
:
wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-root
Code language: JavaScript (javascript)
Le résultat obtenu nous montre qu’il n’y a pas de clé primaire (primary key) qui est normalement option_id
et qu’il n’y a pas de restriction unique imposée sur la colonne option_name
:
+--------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+-------+
| option_id | bigint(20) unsigned | NO | | NULL | |
| option_name | varchar(191) | YES | | NULL | |
| option_value | longtext | NO | | NULL | |
| autoload | varchar(20) | NO | | yes | |
+--------------+---------------------+------+-----+---------+-------+
Code language: PHP (php)
Et c’est là que le bât blesse – voici à quoi ressemble la structure standard de la table wp-options
:
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| option_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| option_name | varchar(191) | NO | UNI | NULL | |
| option_value | longtext | NO | | NULL | |
| autoload | varchar(20) | NO | MUL | yes | |
+--------------+---------------------+------+-----+---------+----------------+
Code language: PHP (php)
Ajouter la Primary Key manquante à wp_options
On ajoute à la colonne option_id
la clé primaire qui lui manque:
wp db query "ALTER TABLE $(wp db prefix --allow-root)options MODIFY option_id INT AUTO_INCREMENT PRIMARY KEY;" --allow-root
Code language: JavaScript (javascript)
Et on vérifie le résultat:
wp db query "DESCRIBE $(wp db prefix --allow-root)options" --allow-root
Code language: JavaScript (javascript)
Ajouter la contrainte Unique qui manque à wp_options
Pour ajouter la contrainte UNIQUE
à la colonne option_name
, on lance:
wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-root
Code language: JavaScript (javascript)
Là, il est possible que cela bloque, suivant ce qui se trouve dans votre table wp_options
.
Résoudre le problème des doublons
Si vous obtenez une erreur comme :
ERROR 1062 (23000) at line 1: Duplicate entry 'jetpack_available_modules' for key 'option_name'
Code language: JavaScript (javascript)
alors cela signifie qu’il existe des enregistrements option_name
dupliqués, des doublons qui portent le même nom alors que chaque nom option_name
devrait être unique.
On peut obtenir la liste des enregistrements option_name
doublons avec cette requête:
wp db query "SELECT option_name, COUNT(*) optioncount FROM $(wp db prefix --allow-root)options GROUP BY option_name HAVING optioncount > 1 ORDER BY optioncount DESC;" --allow-root
Code language: JavaScript (javascript)
Par ordre ascendant, voici la liste des doublons:
+---------------------------------------------+-------------+
| option_name | optioncount |
+---------------------------------------------+-------------+
| jetpack_callables_sync_checksum | 47123 |
| jetpack_sync_full_config | 50 |
| jetpack_sync_full_enqueue_status | 43 |
| jpsq_sync_checkout | 10 |
| jetpack_sync_full__params | 5 |
| jetpack_sync_settings_sync_via_cron | 4 |
| jetpack_sync_full__started | 4 |
+---------------------------------------------+-------------+
On peut supprimer automatiquement tous les doublons option_name
de deux manières différentes, soit en utilisant la plus vieille valeuroption_id
(donc la plus petite valeur d’ID), soit en utilisant la valeuroption_id
la plus récente (plus grande valeur d’ID).
Garder le doublon option_name le plus ancien
Voici la requête SQL qui montre uniquement le plus ancien enregistrement (MIN
) option_id
pour chaque doublon de valeur option_name
:
SELECT *
FROM wp options
WHERE option_id NOT IN
(SELECT *
FROM
(SELECT MIN(n.option_id)
FROM wp_options
GROUP BY n.option_name) x)
Code language: CSS (css)
Une fois que vous avez vérifié le résultat, on peut passer à la suppression.
Cette requête SQL garde l’enregistrement (MIN
) option_id
le plus ancien de tous les doublonsoption_name
et supprime tous les enregistrements plus récents que la valeur trouvée:
DELETE
FROM wp options
WHERE option_id NOT IN
(SELECT *
FROM
(SELECT MIN(n.option_id)
FROM wp_options n
GROUP BY n.option_name) x)
Code language: CSS (css)
Voici l’équivalent wp-cli
:
wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MIN(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-root
Code language: JavaScript (javascript)
Garder le doublon option_name le plus récent
Cette requête SQL ne montre que les enregistrements option_id
les plus récents (MAX
) pour tous les doublons option_name
:
SELECT *
FROM wp_options
WHERE option_id NOT IN
(SELECT *
FROM
(SELECT MAX(n.option_id)
FROM wp_options n
GROUP BY n.option_name) x)
Code language: CSS (css)
Et voici la requête qui permet de garder les enregistrements option_id
les plus récents (MAX
) pour tous les doublons option_name
en supprimant tous les doublons les plus anciens:
DELETE
FROM wp_options
WHERE option_id NOT IN
(SELECT *
FROM
(SELECT MAX(n.option_id)
FROM wp_options n
GROUP BY n.option_name) x)
Code language: CSS (css)
Voici l’équivalent wp-cli pour garder l’enregistrement option_name
le plus récent:
wp db query "DELETE FROM $(wp db prefix --allow-root)options WHERE option_id NOT IN (SELECT * FROM (SELECT MAX(n.option_id) FROM $(wp db prefix --allow-root)options n GROUP BY n.option_name) x)" --allow-root
Code language: JavaScript (javascript)
Vérifier les clés et contraintes de la table wp_options
Ajoutons de nouveau la contrainte UNIQUE
sur la colonne option_name
:
wp db query "ALTER TABLE $(wp db prefix --allow-root)options ADD UNIQUE (option_name);" --allow-root
Code language: JavaScript (javascript)
Si vous n’obtenez pas d’erreur, vérifiez la table une nouvelle fois pour constater les changements:
wp db query "DESCRIBE $(wp db prefix --allow-root)options;" --allow-root
Code language: JavaScript (javascript)
Kaboom! Votre table wp_options
possède maintenant une PRIMARY KEY
sur la colonne option_id
et la contrainte UNIQUE
sur la colonne option_name
:
+--------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------------------+------+-----+---------+----------------+
| option_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| option_name | varchar(191) | NO | UNI | | |
| option_value | longtext | NO | | NULL | |
| autoload | varchar(20) | NO | | yes | |
+--------------+---------------------+------+-----+---------+----------------+
Code language: PHP (php)
Je vous conseille de vérifier la structure de la table de temps à autre, notamment si vous constatez une prise de poids anormale en très peu de temps