Come Ottimizzare un Sito WordPress per Milioni di Post
Sto lavorando su un sito web per un'azienda che molto probabilmente creerà milioni di post attraverso un custom post type. Si tratta di preghiere, quindi fondamentalmente l'utente sul front-end invia solo una breve frase tramite un form. All'azienda interessa solo il contenuto del post e la data di pubblicazione. Il sito non è ancora stato lanciato e hanno già più di 120.000 post, quindi sono assolutamente serio quando parlo di milioni.
Quindi, alcune domande sull'ottimizzazione:
- Supponiamo che io abbia una categoria 'in evidenza' in un custom post type che ha 500.000 post. La categoria in evidenza ha solo 500 post. Se creo una query per i post in evidenza, sto interrogando tutti i 500.000 post o solo i 500 in evidenza? E se volessi visualizzare solo i dieci post più recenti in evidenza?
- Quando salvo questo custom post type nel database, ci sono accorgimenti che posso adottare per ridurre le risorse del server, specialmente considerando che le uniche cose realmente necessarie sono il contenuto del post e la data?
- Dovrei proprio utilizzare un custom post type? Mi piace in linea di principio perché è ben integrato nell'amministrazione di WordPress, ma se ci sono significativi svantaggi in termini di prestazioni, suppongo di poter fare qualcosa di diverso.
Non ho mai lavorato su un progetto di questa scala, quindi sono un po' più preoccupato del solito riguardo alle prestazioni. Grazie per qualsiasi aiuto!

1. Imposta la query prima che WP_Query venga eseguito
Questo sembra essere l'aspetto più importante da tenere a mente quando si cerca di mantenere al minimo le query al database, poiché l'unica opportunità per modificare la query è, ovviamente, prima che venga eseguita nel database SQL.
Query normali
Per una query normale, WordPress utilizza la funzione wp()
, che a sua volta chiama $wp->main( $query_vars )
. Le variabili "is_" dei tag condizionali vengono impostate prima di passarle a WP_Query->get_posts()
, che le converte in una query MySQL e infine le memorizza nell'oggetto $wp_query. È possibile filtrare la query prima che venga effettivamente eseguita nel database SQL.
L'azione pre_get_posts
si aggancia a questo processo, permettendoti di modificare la query prima che venga passata a WP_Query->get_posts()
.
Ad esempio, se vuoi filtrare la query per i post nella categoria "in-evidenza", utilizzerai add_action( 'pre_get_posts', 'nome_tua_funzione' );
e includerai il tag condizionale in_category
all'interno di nome_tua_funzione
.
function nome_tua_funzione( $query ) {
if ( $query->in_category( 'in-evidenza' ) && $query->is_main_query() ) {
// Sostituisci 123 con l'ID della categoria "in-evidenza".
$query->set( 'cat', '123' );
}
}
add_action( 'pre_get_posts', 'nome_tua_funzione' );
Vedi Plugin API/Action Reference/pre get posts « WordPress Codex
Richieste di pagina
Per quanto riguarda i template di pagina, come la pagina archivio per la categoria "in-evidenza", i tag condizionali non funzioneranno dal filtro pre_get_posts
. Ad esempio, non puoi usare is_category
per verificare la pagina archivio perché WP_Query non è stato ancora eseguito.
Invece, dovresti modificare la query principale per le richieste di pagina con un new WP_Query
che sarebbe qualcosa come $query = new WP_Query( 'cat=123' );
. Questo esegue la query con l'argomento appropriato impostato fin dall'inizio.
Vedi Class Reference/WP Query « WordPress Codex
2. Salvataggio nel database
Puoi utilizzare il filtro wp_insert_post_data
assicurandoti che solo i $data rilevanti per il tuo custom post type vengano restituiti a wp_insert_post
. Assicurati di includere un'istruzione condizionale per verificare il tuo custom post type.
Plugin API/Filter Reference/wp insert post data « WordPress Codex
Questo hook viene chiamato dalla funzione wp_insert_post
, che a sua volta viene chiamata da wp_update_post quando aggiorni il tuo custom post type, solitamente salvando una bozza o pubblicando il post.
Dovrai fare dei benchmark personalmente, poiché non posso garantire l'importanza dell'ottimizzazione nel ridurre i dati che vengono aggiornati nel database.
3. I custom post type influiscono sulle prestazioni?
Nella mia esperienza, i custom post type sono uno strumento potente per gestire i contenuti. Non conosco altri modi per gestire i post in tutti i modi che permette con un utilizzo minore di risorse. Personalmente, mi concentrerei sulla riduzione del numero di query effettuate ovunque possibile.
C'era un problema di prestazioni legato alla struttura dei permalink che causava un calo delle prestazioni quando iniziava con del testo invece che con un numero.3 Questo era particolarmente problematico per i siti con un gran numero di pagine, ma è stato risolto a partire da WordPress 3.3.
Parlo dei permalink solo perché lo slug è solitamente la prima parte della struttura del permalink, che potrebbe aver influenzato le prestazioni prima della versione 3.3. A parte questo, non sono a conoscenza di altri problemi di prestazioni derivanti dall'uso dei custom post type.
Altre opzioni per le prestazioni
Transient
Questo non è un sostituto per mantenere le query al minimo nel tuo codice, ma puoi usare set_transient per memorizzare le query per un certo periodo, evitando così nuove query. Ecco l'esempio utilizzato nel post di Dave Clements. Nota anche che raccomanda di aggiungere un'azione save_post
per eliminare il transient ogni volta che un custom post type viene aggiornato.
<?php // QUERY PER I CONTENUTI IN EVIDENZA
if( false === ( $its_query = get_transient( 'its_query' ) ) {
$pttimestamp = time() + get_option('gmt_offset') * 60*60;
$its_query = new WP_Query( array(
'post_type' => 'spotlight',
'posts_per_page' => 1,
'post__not_in' => $do_not_duplicate,
'meta_query' => array(
array(
'key' => '_hpc_spotlight_end_time',
'value' => $pttimestamp,
'compare' => '>'
)
)
) );
set_transient( 'its_query', $its_query, 60*60*4 );
}
if( have_posts() ) { // NASCONDI LA SEZIONE SE NON CI SONO CONTENUTI IN EVIDENZA ?>
// QUI VA IL LOOP: NON IMPORTANTE PER L'ESEMPIO
<?php } ?>
Ottimizzazione aggiuntiva delle query
Thomas Griffin offre alcuni buoni consigli nel suo tutorial Ottimizzare le query di WordPress. Ecco una breve lista dei suoi suggerimenti:
Imposta
'cache_results' => false
nelle query occasionali se il tuo server non utilizza cache persistente come Memcached. Le query occasionali sono descritte come "query utilizzate per mostrare piccole quantità di dati. Potrebbe essere che vuoi solo visualizzare i titoli dei post correlati al post corrente, o potresti voler mostrare un menu a discesa di post da selezionare per un'impostazione particolare."Il suo esempio:
$query = get_posts( array( 'posts_per_page' => 1, 'cache_results' => false ) );
Imposta
'no_found_rows' => true
dove non è necessaria la paginazione. Questo "bypassa il conteggio dei risultati da parte di MySQL per vedere se è necessaria la paginazione o meno."Il suo esempio:
$query = new WP_Query( array( 'posts_per_page' => 1, 'no_found_rows' => true ) );
Esegui query solo per gli ID dei post se è tutto ciò di cui hai bisogno
'fields' => 'ids'
inget_posts
. Questo dovrebbe ridurre significativamente la quantità di dati restituiti, che è piuttosto elevata per post se guardi la Descrizione del database « WordPress CodexIl suo esempio:
$query = get_posts( array( 'posts_per_page' => 1, 'fields' => 'ids' ) );
Oltre a quest'ultimo suggerimento, lo stesso ragionamento può essere applicato quando hai bisogno solo di uno o pochi campi del post utilizzando get_post_field.
Avere una solida comprensione di come funziona la query è essenziale. Più specifiche riesci a essere con le tue query, meno lavoro chiederai al tuo database SQL. Ciò significa che ci sono infinite possibilità per gestire le query del database. Fai attenzione con le query personalizzate per quanto riguarda dove vengono eseguite (è una pagina di amministrazione?), utilizza una corretta sanificazione nelle query dirette e cerca di utilizzare le funzioni native di WordPress dove ti permettono di ottenere le stesse prestazioni.

Il tema è completamente personalizzato, quindi stiamo interrogando solo gli elementi assolutamente essenziali. Tuttavia, questi suggerimenti sono estremamente utili. Alla luce di ciò, tornerò indietro e apporterò alcune modifiche alle mie query. ;)

Aggiungerei che dovresti evitare le meta query il più possibile. Sicuramente non eseguire una query su due campi meta contemporaneamente. Questo comporta query doppie e triple che diventano rapidamente un incubo per le prestazioni. I custom post type spesso possono aiutare in questo caso.

Aggiungo anche:
'no_found_rows' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'cache_results' => false
- no_found_rows (boolean) – impostatelo a true quando non avete bisogno di paginazione e non vi serve il conteggio totale dei post trovati.
- cache_results (boolean) – Cache delle informazioni sui post.
- update_post_meta_cache (boolean) – Cache delle meta informazioni dei post.
- update_post_term_cache (boolean) – Cache delle informazioni dei termini dei post.
Utilizzando questi parametri e impostando i valori a FALSE, possiamo rendere la query più veloce evitando l'esecuzione di alcune query aggiuntive al database.
Nota: Non dovremmo usare sempre questi parametri poiché aggiungere elementi alla cache è la cosa giusta da fare, tuttavia possono essere utili in circostanze specifiche e dovrebbero essere considerati solo quando si sa esattamente cosa si sta facendo.

Per favore [modifica] la tua risposta e aggiungi una spiegazione: perché potrebbe risolvere il problema?

Non riesco ad aggiungere il mio commento a questa risposta: https://wordpress.stackexchange.com/a/166699/57674

Come tutte le domande relative a ottimizzazioni premature, questa non può essere risposta con certezza senza conoscere i modelli d'uso esatti, che troppo spesso vengono scoperti solo quando si va in produzione.
In generale, secondo le specifiche di MySQL non dovrebbero esserci problemi con la quantità di dati. Naturalmente, la ricerca dei dati, anche con i migliori algoritmi, sarà più lenta rispetto a tabelle molto più piccole, ma la soluzione è semplice: una CPU più potente.
Potresti voler ottimizzare il modo in cui i metadati vengono memorizzati (ad esempio evitando di memorizzare dati relativi ai ping), ma questo tipo di scelta dipende da cosa fai esattamente, e alla fine potresti comunque aver bisogno di una CPU più potente, quindi potrebbe non valere la pena lo sforzo.
