Post meta vs tabelle separate del database

3 dic 2010, 21:04:49
Visualizzazioni: 28.8K
Voti: 33

Quando si sviluppano plugin che richiedono l'archiviazione dei dati, quali sono i pro e i contro nell'utilizzo di un metodo rispetto all'altro?

La spiegazione fornita nel codex non è dettagliata:

Prima di procedere con la creazione di una nuova tabella, tuttavia, considera se memorizzare i dati del tuo plugin nei Post Meta di WordPress (noti anche come Campi Personalizzati) potrebbe funzionare. Il Post Meta è il metodo preferito; usalo quando possibile/pratico.

1
Commenti

Per tua informazione: MB Custom Table è un plugin che può memorizzare i metadati in tabelle personalizzate invece che nella tabella post meta di WordPress.

Anh Tran Anh Tran
13 dic 2017 12:17:58
Tutte le risposte alla domanda 5
9
37

Beh, se indosso il cappello di uno script kiddie di WP, la mia risposta sarebbe: usa post_meta, sempre.

Tuttavia, mi capita di sapere un paio di cose sui database, quindi la mia risposta è: mai, mai, mai usare un EAV (ovvero la tabella post_meta) per memorizzare dati che potresti aver bisogno di interrogare.

Sul fronte degli indici, fondamentalmente non ce ne sono di utilizzabili nelle tabelle meta. Quindi, se stai memorizzando dati di tipo XYZ e speri di interrogare tutti i post che hanno XYZ con un valore di 'abc', beh... buona fortuna. (Vedi tutti i ticket relativi a utenti/ruoli/permessi nel trac di WP per farti un'idea di quanto possa diventare macabro.)

Sul fronte dei join, raggiungi rapidamente il limite in cui l'ottimizzatore decide di utilizzare un algoritmo generico invece di analizzare la query quando ci sono più criteri di join.

Quindi no, no, no, no. Non usare mai, mai, mai una meta. A meno che ciò che stai memorizzando non sia cosmetico e non faccia mai parte di un criterio di query.

Si riduce tutto alla tua applicazione. Se stai memorizzando, ad esempio, la data di nascita di un regista cinematografico, allora nessun problema. Usa pure una meta quanto vuoi. Ma se stai memorizzando, ad esempio, la data di uscita di un film, saresti pazzo a non usare una tabella separata (o aggiungendo colonne alla tabella posts) e aggiungere un indice a quella colonna.

3 dic 2010 23:13:18
Commenti

Sì, i plugin che sto sviluppando gestiscono dati personalizzati come eventi, notizie, comunicati stampa, offerte di lavoro... Dal di fuori del "Mondo WordPress", l'uso di tabelle non è davvero un'opzione. Ma il consiglio dal WordPress Codex è un po' confuso. Come può essere preferibile avere dati serializzati rispetto a dati normalizzati/strutturati/indicizzati?

Nassif Bourguig Nassif Bourguig
3 dic 2010 23:35:22

Se chiedi allo sviluppatore WordPress medio, probabilmente risponderà "usa un meta" o "usa una tassonomia". E sono d'accordo, fino al punto in cui hai bisogno di interrogare quei dati. Se è così, e credo sia il tuo caso, la mia unica risposta è: aggiungi i campi alla tabella dei post o crea una tabella separata. Altrimenti ti troverai di fronte a enormi problemi di prestazioni quando si tratta di interrogazioni e, ancora più importante per liste di nodi, ordinamento top-n.

Denis de Bernardy Denis de Bernardy
3 dic 2010 23:38:44

Denis, potresti approfondire un po' di più questo punto? Lo trovo molto informativo ma mi piacerebbe avere qualche dato in più. Qualcuno ha fatto dei test? Quali sono esattamente i maggiori svantaggi e limitazioni? Grazie.

Wyck Wyck
4 dic 2010 08:49:07

@Denis - Una difesa piuttosto appassionata contro postmeta, eh? Sai che stai andando fermamente contro l'ortodossia e cadrai dalle buone grazie degli alti sacerdoti della chiesa della poesia del codice se persisterai in tali discorsi, vero? :-) Ma seriamente, non pensi di esagerare un po'? Dipende davvero se ci saranno decine di migliaia di record meta o meno. In molti casi semplicemente non ci sono abbastanza record di cui preoccuparsi. Un sito complesso che sto distribuendo ha circa 10.000 record meta con pochi nuovi record previsti, e va bene (per tua informazione, non è un blog).

MikeSchinkel MikeSchinkel
4 dic 2010 10:52:11

@Mike: 10k righe non sono molte. Quando testo lo schema che sto usando, lo riempio con 200k righe e mi assicuro che nessuna query comune impieghi più di qualche ms. Questo include quelle relative al (grafo orientato delle) autorizzazioni, aggiungerei. Rimando a un thread di SO per ulteriori approfondimenti su pro e contro: http://stackoverflow.com/questions/870808/entity-attribute-value-database-vs-strict-relational-model-ecommerce-question

Denis de Bernardy Denis de Bernardy
4 dic 2010 11:16:04

@Mike: inoltre, non fraintendermi. Uso EAV qua e là. Solo, mi limito a memorizzare dati non essenziali al suo interno, con indici parziali alla tabella meta per il campo occasionale che davvero ne ha bisogno ma chiaramente non appartiene alla tabella principale (un token monouso o una preferenza booleana vengono in mente).

Denis de Bernardy Denis de Bernardy
4 dic 2010 11:24:06

@Denis - Grazie per i commenti. E non fraintendermi, probabilmente tendo molto di più verso la tua prospettiva ma la combinazione di 1.) un dibattito di un'ora con Matt al WordCamp Birmingham sui meriti dei campi tipo Pods e 2.) la semplicità dei meta mi ha portato a concentrare la mia attenzione su altri problemi che potenzialmente potrei cambiare. Al WCB ho capito che finché Matt sarà al comando non cambierà perché (immagino) Matt è così innamorato dell'idea di avere meno tabelle che non si permette di riconoscere gli svantaggi dell'indicizzazione su una chiave da 768 byte. <sigh>

MikeSchinkel MikeSchinkel
4 dic 2010 11:39:40

Hehe. Penso che amerai il CMS che sto sviluppando, se deciderò di rilasciarne una parte o tutto in pubblico. :-)

Denis de Bernardy Denis de Bernardy
4 dic 2010 11:43:20

@Denis - Allora forse dovremmo parlare, perché sto facendo lo stesso (con alcuni piani piuttosto elaborati per il seguito, in realtà.) Potrebbe esserci sinergia...

MikeSchinkel MikeSchinkel
4 dic 2010 12:10:53
Mostra i restanti 4 commenti
4

Se il tuo plugin dovrà gestire MOLTI dati, allora utilizzare la tabella wp_postmeta NON è una buona idea, come dimostrato di seguito:

Prendendo WooCommerce come esempio, in un negozio con circa 30.000 prodotti, ci sarà una media di, diciamo, circa 40 metadati per prodotto (attributi e tutto il resto), 5 immagini per prodotto, il che significa che ci saranno circa 4 metadati per ogni immagine:

30.000 prodotti x 40 metadati ciascuno = 1.200.000 righe in wp_postmeta

+

30.000 prodotti x 5 immagini ciascuno x 4 metadati per immagine = 600.000 righe in wp_postmeta

Quindi, con soli 30.000 prodotti, ti ritroverai con 1.800.000 righe in wp_postmeta.

Se aggiungi più proprietà ai tuoi prodotti o alle immagini dei prodotti, questo numero aumenterà.

Il problema è duplice:

  • I self join sono molto costosi con MySQL
  • La tabella wp_postmeta non è indicizzata a meno che non si utilizzino versioni più recenti di MySQL (ad esempio, nessun indice FULLTEXT per meta_value)

Per fare un esempio da un caso reale:

SELECT meta_value FROM wp_postmeta WHERE meta_key LIKE '_shipping_city'

Questa query, che seleziona la città di spedizione da tutti i dettagli degli ordini, impiega ben ~3 secondi su un server dedicato entry level anche se ci sono solo 5-10 ordini. Questo perché la query viene eseguita su una tabella wp_postmeta che contiene circa 3 milioni di righe in un'installazione live.

Anche la home page risulta piuttosto lenta, perché il tema recupera vari elementi da wp_postmeta - slider, alcune recensioni, alcuni altri metadati. In generale, l'elenco dei prodotti è molto lento e le ricerche sono altrettanto lente quando si elencano i prodotti.

Non puoi risolvere questo problema con mezzi normali. Potresti installare Elastic Search sul tuo server e utilizzare un plugin Elastic Search per WordPress, potresti usare redis/memcached, potresti utilizzare un buon plugin di cache per le pagine, ma alla fine il problema fondamentale rimarrà - recuperare qualsiasi quantità di dati da una tabella wp_postmeta gonfia sarà lento, ogni volta che viene fatto. Sul server dove ho testato la soluzione che ho implementato qui sotto, tutti questi strumenti erano installati, configurati e ottimizzati correttamente, e il sito funzionava accettabilmente bene per gli utenti non loggati o per le query comuni, poiché i plugin di caching entravano in azione.

Ma nel momento in cui un utente loggato cercava di fare qualcosa che non era comune o i cron, i plugin di caching o qualsiasi altra utility dovevano recuperare dati effettivi dal database per memorizzarli nella cache o fare altro, le cose diventavano lentissime.

Quindi ho provato qualcos'altro:

Ho codificato un piccolo plugin per spostare tutti i metadati dei prodotti (postmeta per il post type product) in una tabella personalizzata generata dal codice. Questo plugin ha preso tutti i metadati per ogni post e ha creato una tabella aggiungendo ogni metadato come colonna e inserendo i valori in ogni riga. Ho trasformato il formato EAV in un formato relazionale piatto e orizzontale. Ho anche fatto in modo che il plugin eliminasse i postmeta dai prodotti spostati dalla tabella wp_postmeta.

Approfittandone, ho spostato anche i metadati degli allegati e i metadati di tutti gli altri post type nelle loro tabelle personalizzate.

Poi ho agganciato il filtro get_(post_type)_meta per sovrascrivere il recupero dei metadati e servirlo dalle nuove tabelle personalizzate.

Ora la stessa query di prima, che impiegava ~3 secondi per essere eseguita su wp_postmeta, impiega ~0,006 secondi. Il sito ora si comporta come se fosse una nuova installazione di WP.

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

Naturalmente, fare le cose alla maniera di WordPress è meglio. È effettivamente la norma.

Tuttavia, è anche ovvio che una tabella EAV è molto inefficiente in termini di scalabilità. È infinitamente flessibile e ti permette di memorizzare qualsiasi dato, ma il prezzo che paghi per questo è la performance. È un compromesso fondamentale.

In questo contesto, è difficile dire a qualcuno che intende avere una montagna di dati e - Dio non voglia - eseguire query/ricerche su quei dati di utilizzare sicuramente la tabella wp_postmeta. Il calo di prestazioni sarà notevole.

L'uso di tabelle personalizzate ti permetterà di accumulare dati e mantenerli comunque abbastanza veloci.

Proprio come Pippin Williams, il creatore del plugin Easy Digital Downloads, ha detto che userebbe tabelle personalizzate se iniziasse oggi a codificare il suo plugin, se hai intenzione di creare qualcosa che verrà utilizzato a lungo o che accumulerà molti dati, è più efficiente utilizzare tabelle personalizzate se le progetti bene.

Devi assicurarti che qualsiasi altro sviluppatore di plugin/addon abbia i mezzi per agganciarsi al tuo plugin e manipolare i tuoi dati prima e dopo il recupero. Se lo fai, allora sei a posto.

20 feb 2017 11:55:56
Commenti

Roba interessante! Una cosa da chiarire è che il filtro menzionato "get_(post_type)meta" si chiama in realtà "get(meta-type)_metadata", dove meta-type può essere post, comment o user. Quindi get_post_meta() passerà attraverso il filtro get_post_metadata, indipendentemente dal tipo di post. Il valore restituito dal filtro è ciò che vuoi che sia il valore finale del meta.

Berend Berend
27 feb 2017 08:03:03

get_(meta-type)_metadata -> in effetti funziona con tutti i tipi di post, e infatti la funzione finale che viene visitata è get_post_metadata. Tuttavia il filtro funziona quando lo usi comunque.

unity100 unity100
27 feb 2017 21:38:03

Ciao @unity100 puoi condividere il tuo plugin? O gli snippet di tutti gli hook che hai usato per spostare i postmeta degli allegati su una tabella personalizzata? Grazie

Manu Manu
24 gen 2023 17:16:02

@Manu https://wordpress.org/plugins/meta-accelerator/ è quello che ho testato con WooCommerce, e ha funzionato abbastanza bene. Necessitava di alcune modifiche per vari scopi ma sembrava ne valesse la pena. Potrebbero esserci stati alcuni cambiamenti nella gestione dei meta negli anni e potrebbe aver bisogno di aggiornamenti, ma sarebbe un buon punto di partenza.

unity100 unity100
25 gen 2023 18:27:15
0

Dipende da ciò che stai facendo. Il modo corretto in WordPress è utilizzare le tabelle esistenti, poiché sono state progettate per essere abbastanza flessibili. Tuttavia, occasionalmente potresti incontrare una nuova classe di dati che non può essere inserita in una tabella esistente, ad esempio se volessi memorizzare metadati per le categorie, potresti scegliere di creare una tabella wp_termsmeta.

Tuttavia, solitamente puoi memorizzare i tuoi dati comodamente nelle diverse tabelle esistenti, e dove archiviarli dipende da ciò che fa il tuo plugin.

  • Per impostazioni generali del plugin, utilizza la chiamata API get_option() - verrà anche memorizzata nella cache.
  • Per impostazioni del plugin specifiche per un singolo articolo, utilizza i metadati personalizzati per articolo con get_post_meta(). Di solito è più che sufficiente per ciò che ti serve.

WordPress implementa anche un sistema di caching per velocizzare i tempi di risposta.

3 dic 2010 23:21:39
0

concordo al 100% con Denis. Ma c'è un modo per aggirare il problema.

Il problema nell'usare i post meta per valori da interrogare si presenta quando i valori sono array, ecc. Come in questo esempio:

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

Questo viene memorizzato nel database come una stringa serializzata, che apparirà più o meno così:

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

Quindi, quando vuoi interrogare tutti i post con array['key2'] = 'val 2', WordPress deve estrarre ogni meta entry chiamata array, decomprimerla, testarla e poi passare alla successiva. Questo farà sicuramente crollare il tuo server se il tuo sito ha successo e contiene molti post, pagine, custom post, ecc.

La soluzione dipende dal progetto, e capirai perché. Se memorizzi i dati come var = val, WordPress sarà in grado di cercare senza che PHP debba decomprimere ogni singolo test. Per farlo nello scenario precedente, useresti alcuni namespace e memorizzeresti le meta key:

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

quindi WordPress cercando la key 2 con val 2 sarà in grado di estrarla direttamente. Tuttavia, questo dipende dal progetto. Il mio progetto attuale si basa su circa 20 diversi tipi di dati da memorizzare con ogni custom post, quindi quanto sopra creerebbe semplicemente una tabella enorme da cercare, visto che ci aspettiamo centinaia di migliaia di post. Quindi in quello scenario una tabella personalizzata è l'unica soluzione.

Spero che questo possa aiutare qualcuno

3 dic 2011 13:25:47
0

Per il mio sito su FarmVille :) Ho fatto entrambe le cose ma non l'ho mai completato perché l'ho venduto:

  1. Ho letto l'XML di FarmVille e ho scaricato i dati in una tabella personalizzata
  2. In WordPress avevo creato campi personalizzati automaticamente per ogni campo in quella tabella (e alcuni extra)
  3. Ora il problema è cosa succede se un valore cambia nella tabella o dall'altra parte: i campi personalizzati devono rimanere continuamente sincronizzati

Ho fatto questo perché volevo che da un lato gli utenti potessero modificare il sito WordPress inserendo nuovi dati di FarmVille, ad esempio "una mucca costa 10 monete" MA dall'altro lato dell'integrazione: SE un cambiamento nell'XML significava che la mucca ora costa "20 monete" (tramite il plugin di modifica front-end), questo sarebbe stato dato come opzione dopo: in modo che o l'XML O l'utente avesse ragione (una sorta di sistema wiki).

Quindi ecco un esempio quando si usano entrambi.

4 dic 2010 18:58:30