get_option() vs get_theme_mod(): Perché uno è più lento?

18 lug 2014, 23:06:04
Visualizzazioni: 27.7K
Voti: 22

Ho utilizzato get_theme_mod() per un po' di tempo in vari miei progetti. Ho deciso di sfruttare l'API di Personalizzazione del Tema in WordPress v3.4 quando è diventata disponibile, poiché la consideravo uno strumento indispensabile per i miei clienti.

Dopo un po' di tempo, ho iniziato a notare che i miei siti erano un po' più lenti del solito, e il Customizer in particolare impiegava molto tempo per caricarsi. Attraverso numerose prove ed errori durante la mia investigazione, ho deciso di provare a cambiare il type durante la registrazione delle impostazioni (cioè $wp_customize->add_setting()) da theme_mod a option.

Una volta fatto questo e sostituito tutte le mie chiamate get_theme_mod() con get_option(), ho notato un aumento di velocità molto significativo utilizzando quest'ultima configurazione rispetto alla precedente, sia nel frontend che soprattutto nel Customizer nel backend. Ho esaminato il core di WordPress nel tentativo di trovare una risposta sul perché di questo comportamento, ma non riesco a capire quale sia il particolare problema in questo scenario.

Qualsiasi spunto che la comunità possa avere riguardo al perché get_option() funzioni significativamente più velocemente di get_theme_mod() sarebbe molto apprezzato.

4
Commenti

Se dai un'occhiata in /wp-includes a option.php dove è definita get_option(), e a theme.php dove è definita get_theme_mod(), puoi vedere che quest'ultima in realtà chiama get_option() stessa, agendo come un'estensione che applica anche i filtri necessari. Potrebbe spiegare perché è più lenta.

Jody Heavener Jody Heavener
18 lug 2014 23:20:51

Jody, l'ho pensato anch'io, ma sembra che semplicemente fare riferimento a get_option() e applicare alcuni filtri non dovrebbe rallentarla in modo così significativo come stava accadendo. Sicuramente un ottimo punto di partenza, ma mi chiedo se non ci sia qualcos'altro in gioco qui.

ntg2 ntg2
19 lug 2014 19:36:59

Non c'è alcuna ragione per una differenza di velocità in quel caso, quindi sospetto che qualcos'altro stia causando le differenze percepite. Le modifiche del tema sono memorizzate come opzioni esse stesse.

Otto Otto
19 lug 2014 19:52:00

Il processo di serializzazione/unserializzazione nel recupero del singolo mod potrebbe in qualche modo influire? Mi chiedo se quel lavoro aggiuntivo per estrarre il mod potrebbe essere un collo di bottiglia rispetto al semplice recupero dell'opzione senza bisogno di fare quella operazione. Quando ho cambiato da get_theme_mod() a get_option() la velocità di tutti i progetti è raddoppiata in media sia sul frontend che nel Customizer. Questa è stata l'unica modifica apportata nel tentativo di isolarla da qualsiasi altro effetto collaterale.

ntg2 ntg2
19 lug 2014 20:04:47
Tutte le risposte alla domanda 5
0
23

La risposta è sì, le funzioni theme_mod saranno più lente, ma non in modo significativo, e i benefici superano le differenze.

I theme mod vengono memorizzati come opzioni. Quindi, in sostanza, le funzioni theme_mod sono wrapper attorno alle funzioni delle opzioni.

Innanzitutto, è importante capire che le impostazioni theme_mod vengono memorizzate come un array in una singola opzione, associata al nome specifico del tema. Quindi, se faccio questo:

set_theme_mod('aaa',123);
set_theme_mod('bbb',456);

Quello che ottengo effettivamente nel database è una singola riga di opzioni con il nome theme_mods_nometema che contiene un array serializzato con ('aaa'=>123, 'bbb'=>456) al suo interno.

Ora, get_theme_mod sarà più lento perché in realtà effettua due chiamate get_option. Prima ottiene il nome del tema. Poi, ottiene l'opzione theme_mods_nometema. Quindi già qui c'è una perdita di velocità del 50%. Il resto del lavoro svolto riguarda principalmente i filtri, in quanto c'è una chiamata di filtro aggiuntiva, ma a meno che non abbiate qualcosa su quel filtro, questo è piuttosto insignificante.

Nota che il sistema delle opzioni memorizza i dati recuperati nella cache degli oggetti, quindi non sta effettuando più chiamate al database qui. Solo il primo utilizzo risulta in un accesso al database.

La funzione set_theme_mod sarà un po' più lenta perché effettua quelle stesse due chiamate get_option, poi fa un'altra chiamata get_option per ottenere nuovamente il nome del tema, e infine esegue update_option con l'intero set di opzioni ora modificate. Questo causa un aggiornamento del database, e il fatto che stia inviando molti più dati può effettivamente essere la causa di un rallentamento percepibile. Aggiornare pochi byte è più veloce che aggiornare una riga più grande. Ma non così tanto da notarlo, di solito. A meno che non abbiate un sacco di impostazioni...

Le funzioni theme_mod sono probabilmente da ottimizzare nel complesso, certamente, ma dovresti comunque usarle invece di get_option e simili a causa dei temi figli.

Il problema con l'uso diretto delle righe delle opzioni è che le stai utilizzando direttamente e usi nomi di chiave specifici per le tue impostazioni.

Se ho un tema chiamato "AAA" e creo un tema figlio chiamato "BBB" da utilizzare su un altro sito, il mio tema "AAA" potrebbe utilizzare un'opzione chiamata "example". Quando aggiorno un sito e aggiorno la mia opzione, la stessa opzione si applicherà ora al mio tema figlio. E se non volessi che accadesse? E se volessi che il tema figlio utilizzasse un diverso set di impostazioni delle opzioni?

I theme mod, includendo il nome effettivo del tema (e non un valore hardcoded) come parte della chiave, garantiscono che ogni "tema" sul sito utilizzi il proprio set di impostazioni. Posso passare da uno all'altro e le impostazioni non si trasferiscono tra di loro, rimangono come le ho impostate. Più semplice, più ovvio, più intuitivo.

E se qualche futura modifica del core o un plugin modificherà il funzionamento dei theme_mod, allora otterrete automaticamente i benefici senza alcun cambiamento. I wrapper saranno sempre più lenti, questo è inevitabile, è la natura dei wrapper. Tuttavia, stai ancora scrivendo codice PHP, non linguaggio macchina. Usiamo wrapper come questi per semplificare le cose e separare le funzionalità. I temi non dovrebbero aver bisogno di sapere, o preoccuparsi, di come le loro opzioni sono memorizzate nel database, o di come funziona la denominazione. Le funzioni theme_mod forniscono una soluzione più semplice che è più pulita.

21 set 2014 20:19:21
1

get_theme_mod è semplicemente un wrapper attorno a get_option. In teoria, poiché è un ulteriore livello di astrazione, funzionerà più lentamente, ma nella pratica la differenza non dovrebbe essere abbastanza grande da essere percepita da un essere umano.

Le differenze effettive di velocità possono essere causate se hai del codice lento agganciato agli hook di theme_mod.

20 lug 2014 06:11:37
Commenti

Non è un wrapper. get_theme_mod memorizza il valore in un array serializzato insieme a tutte le opzioni del tema in una riga della tabella wp_options, con la chiave predeterminata "theme_mods_<nome del tema>". get_option memorizza il valore nel campo option_value di una riga nella tabella wp_options, con una chiave che specifichi tu. Per dirla in altro modo, get_theme_mod raggruppa il valore in un array serializzato con tutti gli altri theme mod; get_option invece no.

tklodd tklodd
26 lug 2022 00:06:38
0

Potrebbe esserci qualcosa che accade nel Customizer allora? Sto vedendo la stessa cosa segnalata dall'utente originale qui.

Posso confermare che con circa 30 opzioni il tempo di caricamento del mio Customizer è sceso da circa 3 secondi a circa 0,5 secondi quando ho sostituito get_theme_mod con get_option.

Chiamando i metodi direttamente vedo una differenza di 2ms.

Risultati del test (https://gist.github.com/anonymous/d98a46d00d52d40e7dec)

Potrebbe non essere evidente quando si confrontano le API direttamente, ma deve esserci qualcosa nel modo in cui vengono utilizzate nel Customizer.

22 lug 2014 00:55:03
1

Puoi TESTARE IL TEMPO di get_option (100 iterazioni) utilizzando questo codice (inseriscilo in functions.php o altrove):

add_action('wp','My_Test');
function My_Test(){
    var_dump(microtime(true));
    for ($i=1; $i<100; $i++) { get_option('blogdescription'); }
    var_dump(microtime(true));
    for ($i=1; $i<100; $i++) { get_theme_mod('blogdescription'); }
    var_dump(microtime(true));
    exit;
}   




Altri Pensieri

Non so se faccia una differenza (forse gli sviluppatori di WordPress lo sanno meglio), ma ho pensato che se un sito ha un ALTO traffico e, ad ogni caricamento di pagina, deve recuperare centinaia di opzioni, cosa succederebbe se unissi molte opzioni in un'unica get_option? In questo modo:

update_option('my_extra_optss',  array(
      'myNAME' => 'George',
      'myAGE'  => 43 ));

poi:

$x = get_option('my_extra_optss');
$x['myNAME'];
$x['myAGE'];
................

Questo renderebbe il sito un po' più veloce?

11 lug 2015 13:14:12
Commenti

Questo è esattamente ciò che get_theme_mod fa già. Tutte le modifiche al tema sono già unite in una singola opzione. Ogni volta che chiami get_theme_mod effettua due chiamate al database la prima volta, e zero chiamate al database successivamente.

Otto Otto
17 set 2016 01:13:29
1

TL;DR: Se sei uno sviluppatore di temi, dovresti usare get_theme_mod

Risposta completa:

Se hai 100 chiamate get_option, vengono eseguite 100 query al tuo database.

Se hai 100 chiamate get_theme_mod, viene eseguita solo 1 query al tuo database.

Perché? Perché tutte le modifiche del tema sono memorizzate in un'unica riga del database e verranno chiamate una sola volta, mentre ogni opzione è una riga e 100 chiamate get_option si tradurranno in 100 query al database e, naturalmente, rallenteranno il tuo sito.

Se il tuo tema ha molte opzioni, usare get_theme_mod ridurrà significativamente il numero di query al database.

Puoi verificare le prestazioni e il numero di query con il plugin Query Monitor

9 lug 2019 07:42:25
Commenti

Questo è leggermente incorretto. La funzione get_theme_mod utilizza get_theme_mods - https://developer.wordpress.org/reference/functions/get_theme_mods/ - che in realtà esegue 2 funzioni get_option. Quindi 100 chiamate a get_theme_mod effettivamente fanno 2 richieste al database ;)

WPExplorer WPExplorer
15 apr 2020 01:58:35