Post méta vs tables de base de données distinctes

29

Lors du développement de plugins nécessitant un stockage de données, quels sont les avantages et les inconvénients de l'utilisation d'une méthode ou d'une autre?

L' explication donnée dans le codex n'est pas détaillée:

Avant de vous lancer dans une toute nouvelle table, cependant, demandez-vous si le stockage des données de votre plugin dans Post Meta de WordPress (alias Champs personnalisés) fonctionnerait. Post Meta est la méthode préférée; utilisez-le lorsque cela est possible / pratique.

Nassif Bourguig
la source
FYI: MB Custom Table est un plugin qui peut stocker des métadonnées dans des tables personnalisées au lieu de la post-méta-table de WP.
Anh Tran

Réponses:

30

Eh bien, si je prends le chapeau d'un gamin de script WP, ma réponse serait: utilisez toujours post_meta.

Cependant, je connais une ou deux choses sur les bases de données, donc ma réponse est: jamais, jamais, jamais, utilisez un EAV (aka la table post_meta) pour stocker des données que vous pourriez avoir besoin d'interroger.

Sur le front de l'index, il n'y en a fondamentalement aucun à utiliser dans les méta-tables. Donc, si vous stockez le type de données XYZ et espérez que vous interrogerez tous les messages qui ont XYZ avec une valeur de 'abc', eh bien ... bonne chance. (Voir tous les tickets liés aux utilisateurs / rôles / caps dans le WP trac pour vous donner une idée de la façon dont il peut être sanglant.)

Sur le front de la jointure, vous tombez rapidement sur la limite à laquelle l'optimiseur décide d'utiliser un algorithme générique au lieu d'analyser la requête lorsqu'il existe plusieurs critères de jointure.

Ainsi, non, non, non, non. N'utilisez jamais, jamais, jamais une méta. Sauf si ce que vous stockez est cosmétique et ne fera jamais partie d'un critère de requête.

Il se décompose sur votre application. Si vous stockez, disons, la date de naissance d'un réalisateur de film, ce n'est pas grave. Utilisez une méta tout ce que vous voulez. Mais si vous stockez, disons, la date de sortie d'un film, vous ne devriez pas utiliser une table distincte (ou ajouter des colonnes à la table des publications) et ajouter un index à cette colonne.

Denis de Bernardy
la source
1
Oui, les plugins que je développe gèrent des données personnalisées comme des événements, des actualités, des communiqués de presse, des offres d'emploi ... De l'extérieur de "WordPress World", l'utilisation de tableaux n'est pas vraiment une option. Mais les conseils du WordPress Codex sont un peu déroutants. Comment les blocs de données sérialisés peuvent-ils être préférés aux données normalisées / structurées / indexées?
Nassif Bourguig
1
Si vous demandez au développeur WP moyen, il répondra probablement «utiliser une méta» ou «utiliser une taxonomie». Et je suis d'accord, jusqu'à ce que vous ayez besoin de l'interroger. Si c'est le cas, et je pense que c'est votre cas, ma seule réponse est d'ajouter les champs à la table des publications ou de créer entièrement une table séparée. Sinon, vous rencontrez d'énormes problèmes de performances en ce qui concerne les requêtes et, plus important encore pour les listes de nœuds, le tri top-n.
Denis de Bernardy
1
Denis seriez-vous en mesure de nous en dire un peu plus à ce sujet, je trouve cela très instructif mais j'aimerais avoir plus de données, quelqu'un a-t-il fait des tests?, Quels sont exactement les principaux inconvénients et limites, merci.
Wyck
6
@Denis - Un plaidoyer passionné contre le postmeta, hein? Vous savez que vous allez fermement contre l'orthodoxie et vous tomberez des bonnes grâces des grands prêtres de l'église de la poésie codée si vous persistez dans un tel discours, n'est-ce pas? :-) Mais sérieusement, ne pensez-vous pas que vous surestimez un peu? Cela dépend vraiment de la présence ou non de dizaines de milliers de méta enregistrements. Dans de nombreux cas, il n'y a tout simplement pas assez d'enregistrements à craindre. Un site complexe que je déploie a environ 10 000 méta enregistrements avec peu de nouveaux enregistrements prévus, et ça va (fyi, ce n'est pas un blog.)
MikeSchinkel
1
@Denis - Merci pour les commentaires. Et ne vous méprenez pas, je penche probablement beaucoup plus vers votre point de vue, mais la combinaison de 1.) un débat d'une heure avec Matt à WordCamp Birmingham sur les mérites des champs de type Pods et 2.) la simplicité des méta a dû démissionner pour concentrer mon attention sur d'autres questions que je pourrais potentiellement changer. Au WCB, je suis reparti en réalisant que tant que Matt serait en charge, cela ne changerait pas parce que (je suppose) Matt est tellement amoureux de l'idée de moins de tables qu'il ne se permettra pas de reconnaître les inconvénients de l'indexation sur un 768 octets. clé. <soupir>
MikeSchinkel
5

Si votre plugin va avoir BEAUCOUP de données, alors utiliser le wp_postmetan'est PAS une bonne idée comme démontré ci-dessous:

En prenant WooCommerce comme exemple, dans un magasin avec environ 30 000 produits, il y aura en moyenne environ 40 méta post (attributs et tout) par produit, 5 images de produit par produit, ce qui signifie qu'il y aura environ 4 méta d'image pour chaque image:

30 000 produits x 40 méta chacun = 1 200 000 lignes en wp_postmeta

+

30 000 produits x 5 images chacun x 4 méta d'image pour chacun = 600 000 lignes en wp_postmeta

Donc, avec seulement 30 000 produits, vous envisagez d'avoir 1 800 000 lignes wp_postmeta.

Si vous ajoutez plus de propriétés à vos produits ou à vos images de produits, ce nombre se multipliera.

Le problème est double:

  • Les auto-jointures coûtent très cher avec MySQL
  • wp_postmetala table n'est pas indexée sauf si vous utilisez des versions ultérieures de mysql (c'est-à-dire pas d'index FULLTEXT pour meta_value)

Pour donner un exemple à partir d'un cas réel:

SELECT meta_value FROM wp_postmeta WHERE meta_key LIKE '_shipping_city'

Cela sélectionne la ville d'expédition de tous les détails de la commande à environ 3 secondes sur un serveur dédié d'entrée de gamme, même s'il y a 5 à 10 commandes . En effet, la requête est exécutée à partir d'une wp_postmetatable qui contient environ 3 millions de lignes dans l'installation en direct.

Même la page d'accueil est assez lente, car le thème tire divers éléments de wp_postmeta- curseurs, quelques encarts de révision, quelques autres méta. En général, la liste des produits est très lente, les recherches sont également lentes lors de la liste des produits.

Vous ne pouvez pas résoudre ce problème par tout moyen normal. Vous pouvez mettre Elastic Search sur votre serveur et utiliser un plugin Elastic Search dans Wordpress, vous pouvez utiliser redis / memcached, vous pouvez utiliser un bon plugin de cache de page, mais à la fin le problème fondamental restera - récupérer toute quantité de données à partir d'un ballonnement wp_postmetala table sera lente, chaque fois que cela sera fait. Sur le serveur sur lequel j'ai testé la solution que j'ai implémentée ci-dessous, tous ces éléments ont été installés et configurés correctement et optimisés, et le site a fonctionné convenablement bien pour les utilisateurs non connectés ou les requêtes courantes depuis la mise en cache des plugins.

Mais au moment où un utilisateur connecté a essayé de faire quelque chose qui n'était pas communément fait ou les crons, les plugins de mise en cache ou tout autre utilitaire ont voulu récupérer les données réelles de la base de données pour les mettre en cache ou faire autre chose, les choses se sont ralenties.

J'ai donc essayé autre chose:

J'ai codé un petit plugin pour prendre toutes les méta du produit (postmeta pour le produit de type post ) dans une table personnalisée générée par le code. Ce plugin a pris toutes les méta pour chaque publication et a créé un tableau en ajoutant chaque méta en colonnes et en insérant les valeurs dans chaque ligne. J'ai transformé le format EAV en un format relationnel horizontal et plat. J'ai également eu le plugin pour supprimer postmeta de tous les produits déplacés de la wp_postmetatable.

Pendant que j'y suis, j'ai déplacé le postmeta des pièces jointes et tous les autres méta des types de messages vers leurs propres tables.

Ensuite, je me suis accroché au get_(post_type)_metafiltre pour remplacer la récupération des métadonnées pour les servir à partir de nouvelles tables personnalisées.

Maintenant, la même requête que précédemment, qui prenait ~ 3 secondes à récupérer, wp_postmetaprend ~ 0,006 seconde. Le site se comporte désormais comme s'il s'agissait d'une nouvelle installation WP.

....................

Naturellement, il est préférable de faire les choses à la manière de Wordpress. C'est en fait la norme.

Cependant , il est également évident que la table EAV est très inefficace dans la mise à l'échelle. Il est infiniment flexible et vous permet de stocker toutes les données, mais le prix que vous payez pour cela est la performance. C'est un compromis fondamental.

Dans ce contexte, il est difficile de dire à quelqu'un qui a l'intention d'avoir une tonne de données et - Dieu nous en préserve - de rechercher / rechercher sur ces données pour utiliser la wp_postmetatable à coup sûr. Le succès de performance sera formidable.

L'utilisation de vos tableaux personnalisés permettra à vos données de s'accumuler et de rester suffisamment rapides.

Tout comme la façon dont Pippin Williams, le créateur du plugin Easy Digital Downloads, a indiqué qu'il utiliserait des tableaux personnalisés s'il commençait à coder son plugin, si vous allez créer quelque chose qui sera utilisé pendant longtemps ou accumuler beaucoup de données, il est plus efficace d'utiliser vos tableaux personnalisés si vous les concevez bien.

Vous devez vous assurer que tout autre développeur de plugin / addon a les moyens de se connecter à votre plugin pour manipuler vos données avant et après la récupération des données. Si vous faites cela, alors vous êtes assez solide.

unité100
la source
1
Des trucs intéressants! Une chose à clarifier est que le filtre "get_ (post_type) _meta" mentionné est en fait appelé "get_ (meta-type) _metadata", où le méta-type est soit post, comment ou user. Ainsi, get_post_meta () passera par le filtre get_post_metadata, quel que soit le type de publication. La valeur de retour du filtre est ce que vous voulez que la méta-valeur finale soit.
Berend
get_ (meta-type) _metadata -> en effet, cela fonctionne avec tous les types de messages, et en effet la fonction finale visitée est get_post_metadata. Cependant, le filtre fonctionne quand vous l'utilisez quand même.
Unity100
2

Cela dépend de ce que vous faites. La méthode WP consiste à utiliser les tables existantes, car elles ont été conçues pour être suffisamment flexibles, mais vous atteindrez parfois une nouvelle classe de données qui ne peut pas être placée dans une table existante, par exemple si vous vouliez des métadonnées de catégorie , vous pouvez choisir de créer une table wp_termsmeta.

Cependant, vous pouvez généralement stocker vos données assez confortablement dans les différentes tables existantes, et l'endroit où vous stockez vos données dépend de ce que fait votre plugin.

  • Pour les paramètres généraux du plugin, utilisez l' appel API get_option () - ce sera également mis en cache.
  • Pour les paramètres de plug-in spécifiques à une publication individuelle, utilisez les métadonnées personnalisées par publication avec get_post_meta () . C'est généralement suffisant pour ce dont vous avez besoin.

La mise en cache est implémentée dans WordPress pour accélérer également votre temps de réponse.

Dan Smart
la source
1

d'accord avec denis 100%. Mais il existe un moyen de contourner cela.

Le problème avec l'utilisation de la méta post pour les valeurs à interroger est lorsque les valeurs sont des tableaux, etc.

array(
'key1' => 'val 1',
'key2' => 'val 2'
);

Cela est stocké dans la base de données sous la forme d'une chaîne sérialisée, qui ressemblera à ceci:

{array["key1"]...{}...}

Donc, lorsque vous souhaitez interroger tous les messages avec array['key2'] = 'val 2'wp, il faut extraire chaque entrée de méta appelée tableau, la décompresser, la tester, puis passer à la suivante. Cela fera définitivement tomber votre serveur si votre site est un succès et a beaucoup de publications, pages, publications personnalisées, etc.

La solution dépend du projet et vous comprendrez pourquoi. Si vous deviez stocker les données sous forme de var = valfichier, alors wp pourra effectuer une recherche sans avoir php pour décompresser chaque test. Pour ce faire, dans le scénario ci-dessus, vous utiliseriez un espace de noms et stockeriez les méta-clés:

_array_key1 = 'val 1';
_array_key2 = 'val 2';

alors wp recherchant la clé 2 avec val 2 pourra la retirer immédiatement. Cela dépend cependant du projet. Mon projet actuel repose sur environ 20 types de données différents à stocker avec chaque publication personnalisée, de sorte que ce qui précède ne ferait que créer un tableau massif à rechercher, vu comment nous attendons des centaines de milliers de publications. Donc, dans ce scénario, une table personnalisée est le seul moyen.

J'espère que cela aide quelqu'un

Daithí
la source
0

Pour mon site FarmVille :) J'ai fait les deux mais je ne l'ai jamais fini car je l'ai vendu:

  1. J'ai lu le xml farmville et jeté les données dans un tableau personnalisé
  2. Dans WordPress, j'avais des champs personnalisés créés automatiquement pour chaque champ de cette table (et certains supplémentaires)
  3. Maintenant, inquiétez-vous de ce qui se passe si une valeur change dans la table ou de l'autre côté: le champ personnalisé car ils doivent être synchronisés en continu

Je l'ai fait parce que je voulais d'une part que les utilisateurs modifient le site wordpress en entrant de nouvelles données farmville, par exemple "une vache coûte 10 pièces" MAIS du côté de l'intégration: SI un changement dans le xml ment la vache coûte maintenant "20 pièces" (via le plugin d'édition front-end) qui serait donné en option après: afin que soit le XML OU l'utilisateur ait raison (sorte de système wiki).

Voici donc un exemple d'utilisation des deux.

edelwater
la source