J'ai une installation wordpress et j'ai besoin de cette requête pour chaque message:
select post_id, meta_key from wp_postmeta where meta_key = 'mykey' and meta_value = 'somevalue'
J'ai 3M lignes sur cette table, et la requête prend environ 6 secondes pour terminer. Je pense que cela devrait être beaucoup plus rapide. Si je montre l'index de la table, il me renvoie:
SHOW INDEX FROM wp_postmeta
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
wp_postmeta 0 PRIMARY 1 meta_id A 3437260 NULL NULL BTREE
wp_postmeta 1 post_id 1 post_id A 1718630 NULL NULL BTREE
wp_postmeta 1 meta_key 1 meta_key A 29 191 NULL YES BTREE
Si je fais une explication, cela me retourne ceci:
explain select post_id, meta_key from wp_postmeta where meta_key = 'mykey' and meta_value = 'somevalue'
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE wp_postmeta ref meta_key meta_key 767 const 597392 Using where
Je ne suis pas très bon dans mysql, donc je ne sais pas comment le vérifier ou le résoudre. Pouvez-vous me donner une idée du problème?
Merci à tous.
wp_postmeta
a des index inefficaces. Le tableau publié (voir Wikipedia) est
CREATE TABLE wp_postmeta (
meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
post_id bigint(20) unsigned NOT NULL DEFAULT '0',
meta_key varchar(255) DEFAULT NULL,
meta_value longtext,
PRIMARY KEY (meta_id),
KEY post_id (post_id),
KEY meta_key (meta_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Les problèmes:
AUTO_INCREMENT
n'apporte aucun avantage; en fait, cela ralentit la plupart des requêtes (à cause du fait qu’il faut chercher dans l’index secondaire pour trouver auto_inc id, puis chercher dans les données l’identifiant réel dont vous avez besoin)AUTO_INCREMENT
est un fouillis supplémentaire - à la fois sur le disque et dans le cache.PRIMARY KEY(post_id, meta_key)
- en cluster, gère les deux parties de JOIN
habituelles.BIGINT
est excessif, mais cela ne peut pas être corrigé sans changer d'autres tables.VARCHAR(255)
peut être un problème dans MySQL 5.6 avec utf8mb4
; voir les solutions de contournement ci-dessous.NULL
?Les solutions:
CREATE TABLE wp_postmeta (
post_id BIGINT UNSIGNED NOT NULL,
meta_key VARCHAR(255) NOT NULL,
meta_value LONGTEXT NOT NULL,
PRIMARY KEY(post_id, meta_key),
INDEX(meta_key)
) ENGINE=InnoDB;
L'utilisation typique:
JOIN wp_postmeta AS m ON p.id = m.post_id
WHERE m.meta_key = '...'
Remarques:
PRIMARY KEY
composite va directement à la ligne souhaitée, sans digression via l'index secondaire ni avec la recherche sur plusieurs lignes.INDEX(meta_key)
peut être utile ou non, en fonction des autres requêtes que vous avez.L'erreur "longueur maximale de la clé est 767", ce qui peut arriver dans MySQL 5.6 lorsque vous essayez d'utiliser CHARACTER SET utf8mb4. Effectuez l'une des opérations suivantes (chacune présente un inconvénient) pour éviter l'erreur:
Incompatibilités potentielles
meta_id
n'est probablement pas utilisé nulle part. (Mais c'est risqué de l'enlever).meta_id
et tirer le meilleur parti des avantages de l’utilisation des index suivants: PRIMARY KEY(post_id, meta_key, meta_id), INDEX(meta_id), INDEX(meta_key, post_id)
. (Remarque: en ayant meta_id
à la fin de la PK, il est possible que post_id + meta_key soit non unique.)BIGINT
à un type de données plus petit impliquerait également de changer d'autres tables.utf8mb4
VARCHAR(191)
nécessiterait que l'utilisateur comprenne que la limite est maintenant le "191" arbitraire au lieu de la limite arbitraire précédente de "255".Commentaire
J'espère que certaines de mes recommandations sont sur la feuille de route WordPress. Pendant ce temps, stackoverflow et dba.stackexchange sont encombrés par "pourquoi WP est-il si lent". Je pense que les corrections apportées ici réduiraient considérablement le nombre de questions de ce type.
Notez que certains utilisateurs passent à utf8mb4 malgré des problèmes de compatibilité. Ensuite, ils ont des ennuis. J'ai essayé de résoudre tous les problèmes rencontrés MySQL.
Tiré du blog de Rick James mysql: source
Si vous recherchez des performances de base de données "prêtes à l'emploi", la méta-table de publication est le mauvais endroit pour stocker les éléments que vous souhaitez rechercher. Dans la façon dont vous décrivez votre requête, il sera bien préférable d’utiliser une taxonomie pour ce cas d’utilisation.
Mais si vous êtes déjà trop "au fond du trou" pour restructurer votre base de données, vous devriez vous pencher sur la solution de mise en cache, qui pourrait ne pas aider à accélérer la requête, mais avec une bonne mise en cache, vous ne subirez le retard qu'une seule fois. Utilisez cron pour générer le cache si nécessaire, et l'impact sur l'utilisateur sera nul.