I transient vengono eliminati automaticamente?
Questa domanda mi è venuta in mente leggendo I feed RSS transient in wp_options non vengono rimossi automaticamente?
I transient dovrebbero scadere ed essere eliminati. Tuttavia l'unico modo in cui vedo gestita questa operazione è quando un transient è scaduto e viene richiesto, solo allora viene eliminato durante la richiesta.
Cosa succede se un transient è scaduto ma non viene mai più richiesto dopo la scadenza? Dalla descrizione nel Codex pensavo fosse implicita una sorta di garbage collection. Ora non ne sono così sicuro e non riesco a trovare alcun codice che esegua tale operazione.
Quindi rimarrà nel database per sempre?
Ora sono
A partire da WordPress 3.7 i transient scaduti vengono eliminati durante gli aggiornamenti del database, vedi #20316
Vecchia risposta
Se nessuno può dimostrarmi il contrario, sembra che i transient non vengano effettivamente eliminati quando scadono. A peggiorare le cose, a differenza delle opzioni, non è garantito che siano memorizzati nel database. Quindi non esiste un modo affidabile per recuperare un elenco di tutti i transient e verificare la loro scadenza.
Ecco del codice improvvisato per eseguire la pulizia se il database viene utilizzato per la memorizzazione:
add_action( 'wp_scheduled_delete', 'delete_expired_db_transients' );
function delete_expired_db_transients() {
global $wpdb, $_wp_using_ext_object_cache;
if( $_wp_using_ext_object_cache )
return;
$time = isset ( $_SERVER['REQUEST_TIME'] ) ? (int)$_SERVER['REQUEST_TIME'] : time() ;
$expired = $wpdb->get_col( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout%' AND option_value < {$time};" );
foreach( $expired as $transient ) {
$key = str_replace('_transient_timeout_', '', $transient);
delete_transient($key);
}
}

$time = $_SERVER['REQUEST_TIME']; e poi utilizzando $time nella query SQL - non farlo. Gestisci con maggiore attenzione le variabili/valori di $_SERVER per prevenire SQL injection.

@hakre hm... l'ho preso da una presentazione sulle prestazioni PHP che lo raccomandava rispetto all'uso di time()
che può causare bug (l'esecuzione non è istantanea per natura). Il tempo della richiesta viene impostato da PHP stesso, non proviene da alcun tipo di dato fornito dall'utente. Perché è una vulnerabilità?

@Rarst: Non ho detto che non dovresti usarlo, dovresti solo assicurarti che sia codificato in modo sicuro per essere utilizzato all'interno della query SQL. Dovresti farlo con ogni variabile proveniente da una fonte esterna. Le variabili $_SERVER potrebbero non essere impostate come previsto, e invece essere impostate dall'utente che effettua la richiesta. Volevo solo propagare una buona pratica di codifica. Come sempre, per conoscere lo stato reale della disponibilità, consulta la documentazione. Per PHP 4, ad esempio, una tale variabile non esiste e potrebbe essere sovrascritta da un header personalizzato o da una variabile d'ambiente - http://php.net/manual/en/reserved.variables.server.php

@hakre corretto (credo), grazie per il promemoria su PHP4 tra l'altro (non vedo l'ora che WordPress smetta di supportarlo)

A me sembra molto meglio così ;). Speriamo che non ci siano problemi con time() e interi negativi che potrebbero cancellare tutti o nessun transient per sbaglio. Non fidarti mai di un sistema in esecuzione :P

Nel caso non lo sapessi, _ è un carattere jolly per le istruzioni LIKE e idealmente dovrebbe essere escapato. :)

@Denis sì, lo so... Ma nessuna differenza pratica in questa query?.. A meno che qualcuno non riesca a chiamare un'opzione XtransientXtimeoutX o qualcosa del genere.

Non useresti $wpdb->prepare() per proteggerti adeguatamente da dati non sicuri come quelli di cui parlava @hakre? Questo risolverebbe anche il problema dell'escape del '_'. Lo consiglierei, come best practice.

@Tom a parte "per essere davvero sicuri", questa query specifica non ha realmente bisogno di prepare e non mi sono preoccupato di aggiungerlo.

Hai ragione, ora che ci guardo. Probabilmente il (int) è tutta la protezione di cui hai bisogno per quella variabile del server.

Spostando alcuni dei commenti dalla discussione in una risposta, con una rielaborazione e una riformattazione...
In sostanza, quello che conta è che, a meno che non ci si trovi in un caso estremamente particolare, non c'è davvero bisogno di effettuare una "garbage collection" (pulizia) dei transient. Se non li recuperi mai, allora non importa se sono presenti o meno.
Vedi, i transient vengono memorizzati nella tabella delle opzioni (options) per impostazione predefinita. In un'installazione base, la tabella delle opzioni potrebbe contenere circa 100 voci. Ogni transient aggiunge altre due voci, ma anche se ne hai migliaia, non influiscono sulla velocità del sito, poiché non vengono caricati automaticamente.
All'avvio, WordPress carica le opzioni in memoria, ma solo quelle che hanno il flag di autoload attivato. I transient non lo hanno, quindi non vengono caricati in memoria. Solo i transient che vengono effettivamente utilizzati successivamente comportano un costo.
Dal punto di vista del database, la tabella delle opzioni ha indici sia sull'ID dell'opzione che sul nome dell'opzione. I transient vengono sempre caricati in base al nome (chiave), quindi le ricerche per loro sono sempre semplici SELECT su un singolo valore di chiave univoco. Pertanto, la ricerca è O(log(n)) ed è estremamente veloce. Con un Big-O di log(n), dovresti arrivare a milioni e milioni di righe prima che diventi percettibile. Francamente, l'overhead nella configurazione e nella chiusura della query, insieme al trasferimento effettivo dei dati, è molto più lungo. La query stessa viene eseguita in un tempo essenzialmente zero al confronto. Quindi, semplicemente avere righe extra non utilizzate non influisce su nulla se non sull'utilizzo di spazio su disco aggiuntivo.
L'indicizzazione nei database è uno di quei concetti complessi che non hanno senso per chi non ha effettivamente compreso cosa succede dietro le quinte. I database sono progettati per il recupero rapido dei dati, fin dalle fondamenta, e possono gestire questo tipo di cose senza problemi. Questa è una lettura piuttosto buona: http://en.wikipedia.org/wiki/Index_(database)
Ora, la pulizia nel modo più ovvio (chiamando SQL DELETE su di essi) non li elimina effettivamente dal database. Li rimuove solo dall'indice e contrassegna la riga come "eliminata". Ancora una volta, questo è semplicemente come funzionano i database. Per liberare effettivamente lo spazio su disco, devi poi procedere con un OPTIMIZE TABLE, e questa non è un'operazione veloce. Richiede tempo. Probabilmente più tempo di quanto valga la pena. Probabilmente non è sufficiente per garantirti un risparmio in termini di tempo della CPU, nel complesso.
Se hai un caso che causa un'inserimento continuo di nuovi transient che non vengono utilizzati, allora devi trovare il problema sottostante invece. Cosa sta inserendo questi transient? Stanno usando una chiave che cambia o si modifica? Se è così, allora il plugin o il codice che causa questo comportamento dovrebbe essere corretto per, fondamentalmente, non farlo. Questo sarà più utile, perché è probabile che il codice che non li crea correttamente non li recuperi nemmeno, e quindi stia facendo più lavoro del necessario.
D'altra parte, potrebbe esserci un caso in cui i transient vengono creati per qualcosa come ogni post. Questo potrebbe effettivamente essere perfettamente accettabile. Lo faccio io stesso in SFC, per memorizzare i commenti in arrivo da Facebook. Ogni post ha un potenziale transient associato, il che significa due righe extra per post. Se hai 10k post, avrai 20k righe nella tabella delle opzioni (alla fine). Questo non è male o lento, perché ancora una volta, c'è poca differenza tra 100 righe e 20.000 righe per quanto riguarda i database. È tutto indicizzato. È velocissimo. Sub-sotto-millisecondi.
Quando inizi ad avere milioni di righe, allora mi preoccuperei. Quando la dimensione della tabella delle opzioni supera le centinaia di megabyte, allora sarei abbastanza preoccupato da dare un'occhiata più da vicino. Ma in generale, questo non è un problema se non per casi estremi. Sicuramente non è un problema per qualsiasi cosa più piccola di qualcosa come un grande sito di notizie, con centinaia di migliaia di post. E per qualsiasi sito abbastanza grande da avere questo problema, dovresti usare una cache oggetti esterna di qualche tipo, e in quel caso, i transient vengono memorizzati automaticamente lì invece che nel database.

NB: i transient senza scadenza vengono caricati automaticamente, e l'assenza di scadenza è l'impostazione predefinita, quindi quando un'applicazione/plugin crea molti transient senza impostare una scadenza, utilizzeranno porzioni di memoria ad ogni caricamento di pagina/post.

Non c'è motivo di usare un "transient senza scadenza", perché è sostanzialmente identico a una normale "option".

Certo, ma è l'impostazione predefinita. Di conseguenza, molti autori di plugin stanno aggiungendo transient senza scadenza.

Inoltre, non è identico a un'opzione, poiché verrà eliminato quando si utilizza una cache a oggetti -- vedi l'articolo recente su WPEngine per i dettagli.

Bene, la soluzione qui è semplice: non utilizzare quei plugin. Stanno sbagliando. I transient non devono essere usati come sessioni, non dovresti usarli senza una scadenza significativa e non dovrebbero avere chiavi mutabili o che cambiano.

Dipende. Quale sarebbe secondo te un valore predefinito ragionevole da utilizzare?

Ad esempio, 7 giorni. Se un autore di plugin/temi vuole un valore più grande o più piccolo, lo specificherà. Se vogliono l'autoload, non dovrebbero essere costretti a specificare 0 come scadenza (= infinito), ma è quello che devono fare attualmente dato che il parametro di scadenza svolge anche la funzione di parametro sì/no per l'autoload. In ogni caso, la scadenza predefinita non dovrebbe anche comportare autoload=sì come predefinito; sarebbe solo una fonte di problemi.

Secondo la mia opinione ponderata, non specificare una scadenza dovrebbe generare un errore fatale e interrompere il sito. Ma poi non sono io a decidere. Un transient senza scadenza è stupido e privo di significato. Se vuoi usare l'object cache, allora usa direttamente l'object cache con le funzioni wp_cache. Detto ciò, ci sono ticket per far sì che le future versioni di WordPress ripuliscano i transient vecchi, principalmente perché è "antiestetico" più che per qualsiasi altra ragione.

Otto - Non potrei essere più in disaccordo con te. Il problema è che alla fine, con tutti quei transient, la dimensione della tabella diventa ridicola. Non servono milioni di righe per rallentare tutto. Al momento sto gestendo una tabella delle opzioni con oltre 130k righe, che va in hang regolarmente. Poiché il campo "value" è di tipo testo grande, anche cercare solo le righe "autoload" diventa un incubo a livello di performance. Quei campi value sono memorizzati separatamente dal resto dei dati della riga. Anche se logicamente fa parte della stessa tabella, è necessario effettuare join per recuperare le righe desiderate. Join che ora richiedono un'eternità perché i dati necessari sono sparsi ovunque sul disco. Il profiling (usando Jet Profiler per MySQL) lo ha dimostrato.
Aggiungere l'autoload alla chiave cluster potrebbe aiutare a risolvere il problema. Ad esempio, clusterizzare su Autoload DESC, ID ASC permetterebbe alle righe autoload di raggrupparsi insieme per prime sul disco. Ciononostante, penso che ci sarebbe comunque un enorme carico dal punto di vista del database.
Personalmente trovo il design di questo sistema assurdo. La tabella delle opzioni sembra essersi trasformata in un contenitore generico per un sacco di cose. Va bene se il campo value è abbastanza piccolo da essere incluso nella stessa pagina del resto dei dati della riga e può essere indicizzato efficacemente. Sfortunatamente non è questo il caso. Chi ha progettato questo sistema dovrebbe tornare al corso di Database 101.

vero, ma considera che quando è iniziato lo sviluppo di WordPress, nessuno pensava che avrebbe raggiunto il punto di avere migliaia di plugin che utilizzano la tabella delle opzioni come loro archivio dati :)
