I transient vengono eliminati automaticamente?

9 gen 2011, 02:20:17
Visualizzazioni: 35K
Voti: 69

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?

25
Commenti

teoricamente dovrebbero essere rimossi quando viene eseguito il cron (se sono scaduti)

onetrickpony onetrickpony
9 gen 2011 02:34:01

@Ambitious Amoeba non vedo nulla con quella funzionalità collegata al cron. Ecco perché sto chiedendo - sembra essere un presupposto di cui non sono sicuro sia valido.

Rarst Rarst
9 gen 2011 02:37:59

È mia comprensione che i transient non siano veri e propri processi cron, richiedono almeno che qualcuno richieda una pagina per poter essere creati/rimossi (ma sono la cosa migliore dopo un vero processo cron). Non ho monitorato i miei transient, stai vedendo spesso transient che rimangono dopo la scadenza?

t31os t31os
9 gen 2011 18:35:47

@t31os sì, li vedo rimanere in sospeso, ma non ho informazioni su quanto tempo possono rimanere bloccati prima di poter dire definitivamente che non vengono raccolti come spazzatura

Rarst Rarst
9 gen 2011 18:38:59

@Rarst - Anche io non sono sicuro di come venga determinata la pulizia, stai riscontrando questo problema con transient particolari o diversi?

t31os t31os
9 gen 2011 18:46:09

@t31os Non sprecherò tempo a codificare un meccanismo di logging per i transient prima di sapere se dovrebbero effettivamente essere raccolti come spazzatura. :)

Rarst Rarst
9 gen 2011 18:58:46

@Rarst - Non ne ho idea amico, volevo solo condividere qualche pensiero.. :)

t31os t31os
9 gen 2011 19:11:06

sembra che i transient scaduti vengano eliminati quando viene chiamato get_transient - http://core.trac.wordpress.org/browser/tags/3.0.4/wp-includes/functions.php#L721

onetrickpony onetrickpony
9 gen 2011 19:11:44

Quindi non dovresti vedere alcun transient scaduto nel database, a meno che non ci sia stato un problema con delete_option()

onetrickpony onetrickpony
9 gen 2011 19:13:18

@Ambitious Amoeba sì, l'ho menzionato un po' nella domanda. Il mio punto è - il fatto che un transient venga creato non presuppone o garantisce che sarà mai richiesto. Sottolineando la domanda originale - quando e se un transient scaduto viene eliminato se non lo ottengo mai?

Rarst Rarst
9 gen 2011 19:17:47

ma allora qual è il senso di usare i transient?

onetrickpony onetrickpony
9 gen 2011 19:19:58

@Ambitious Amoeba il punto è che i transient sono un meccanismo di caching. Il concetto di cache presuppone dati in scadenza e non garantisce risultati certi. Se la cache non pulisce i dati scaduti allora sta perdendo risorse.

Rarst Rarst
9 gen 2011 19:29:23

dà per scontato che tu pulisca i dati scaduti, ma sì, hai ragione, ci sono situazioni in cui non verrebbero mai eliminati. Come rimuovere un widget che utilizza i transient. Dovresti aprire un ticket sul trac per questo :)

onetrickpony onetrickpony
9 gen 2011 19:36:11

@Rarst - Sembra la cosa perfetta per scrivere una patch e inviarla al trac?

MikeSchinkel MikeSchinkel
9 gen 2011 20:46:39

@MikeSchinkel sìììì... dopo che qualcuno risponderà definitivamente se i dannati transient vengono (o dovrebbero essere) raccolti come garbage :)

Rarst Rarst
9 gen 2011 21:01:55

@Rarst - L'unico modo per esserne sicuri è analizzare il codice passo dopo passo...

MikeSchinkel MikeSchinkel
10 gen 2011 05:29:29

Non hanno bisogno di essere "garbage collected". Se non li recuperi mai, allora non importa se ci sono o meno.

Otto Otto
12 set 2011 05:51:55

@Otto se inizi ad avere decine di migliaia di queste voci spazzatura nella tabella delle opzioni (cosa che può succedere e succede nella pratica, vedi la domanda linkata) penso che sia piuttosto importante, no?

Rarst Rarst
12 set 2011 11:12:09

No, non è affatto così. I database possono contenere milioni e milioni di righe senza rallentamenti apprezzabili. Si chiama "indicizzazione" e rimane incredibilmente veloce anche con tantissime righe: http://en.wikipedia.org/wiki/Index_(database).

Inoltre, chiamare SQL DELETE su di esse non le elimina realmente dal database. Le rimuove solo dall'indice, finché non si esegue anche un OPTIMIZE TABLE sulla tabella, che è un'operazione lunga. Generalmente non c'è bisogno di "pulire" i record in un database. Lascia che il database faccia il suo lavoro. È più bravo di te.

Otto Otto
12 set 2011 12:11:48

Per essere più specifici, potresti notare che i transient nel database hanno il flag autoload impostato su "no", il che significa che non vengono caricati all'avvio. Il rallentamento principale di qualsiasi query sul database è il trasferimento effettivo dei dati dal database al programma. Le query stesse, se scritte correttamente e adeguatamente indicizzate (cioè la query non causa una scansione completa della tabella), richiedono praticamente nessun tempo in confronto. Non importa se hai 100 record o 100.000, poiché fare un semplice SELECT su un campo indicizzato è un'operazione O(log(n)). Questo non cambia davvero finché non si raggiungono 1M+ di record circa.

Otto Otto
12 set 2011 12:26:28

@Otto Potresti spostare questo in una risposta così che l'informazione sia più visibile? Non discuto che ci vorrà un sacco di record spazzatura per mandare tutto in tilt... Ma se qualcosa sta perdendo risorse (cosa che succede facilmente con i transient perché hanno un limite di lunghezza della chiave che non viene controllato, è facile generarne una quantità enorme e non toccarli mai più perché la chiave è danneggiata) prima o poi creerà problemi. Non sto urlando "risolvilo nel core", ma non vedo la pulizia come inutile.

Rarst Rarst
12 set 2011 12:36:39

"Screw things up" è un'affermazione un po' vaga. Il massimo che potrebbe accadere è che il database diventi troppo grande per uno spazio account limitato. Non romperà effettivamente nulla finché non diventerà davvero, davvero enorme. Lavoro con tabelle che contengono 20 milioni di record. Cercare al loro interno è un po' lento, ma non irragionevolmente. Hai ragione riguardo al limite di lunghezza della chiave, ma 45 caratteri sono più che sufficienti per ogni caso realistico che mi viene in mente. Ok, certo, è possibile fare qualcosa di folle, ma succede spesso? Sembra che l'autore del plugin dovrebbe essere avvisato piuttosto che cercare una soluzione alternativa...

Otto Otto
12 set 2011 20:54:56

@Otto "non spesso" e "mai" sono cose diverse. Se dovessi creare un plugin da questo, ho intenzione di aggiungere un avviso anche per la lunghezza della chiave. Tuttavia, non vedo il senso di mantenere dati spazzatura nel database solo perché i transient funzionano così. Potrebbe non essere un bug, ma difficilmente è una funzionalità.

Rarst Rarst
12 set 2011 21:12:59

Il mio punto non è mantenerli nel database solo perché funzionano così. Il mio punto è che cercare di "raccogliere la spazzatura" costa più di quanto risparmi, in quasi tutti i casi. È addirittura controproducente.

Otto Otto
12 set 2011 21:33:04

Ticket correlato su Trac: http://core.trac.wordpress.org/ticket/20316

Stephen Harris Stephen Harris
30 set 2013 00:19:32
Mostra i restanti 20 commenti
Tutte le risposte alla domanda 3
11
53

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);
    }
}
10 gen 2011 11:55:47
Commenti

$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 hakre
10 gen 2011 14:01:55

@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 Rarst
10 gen 2011 14:08:39

@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 hakre
10 gen 2011 14:12:14

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

Rarst Rarst
10 gen 2011 14:19:14

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

hakre hakre
10 gen 2011 14:26:37

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

Denis de Bernardy Denis de Bernardy
10 gen 2011 15:42:05

@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.

Rarst Rarst
10 gen 2011 16:35:31

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 Auger Tom Auger
22 giu 2012 04:31:21

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

Rarst Rarst
22 giu 2012 11:35:16

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

Tom Auger Tom Auger
22 giu 2012 20:24:37

Non dovrebbe essere _transient_timeout_%? Giusto per assicurarsi che sia davvero il prefisso che WP utilizza? ;)

kaiser kaiser
28 lug 2013 18:04:54
Mostra i restanti 6 commenti
9
21

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.

12 set 2011 21:09:10
Commenti

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.

webaware webaware
29 lug 2013 03:48:50

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

Otto Otto
30 lug 2013 02:43:05

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

webaware webaware
30 lug 2013 03:19:35

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.

webaware webaware
30 lug 2013 03:21:32

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.

Otto Otto
30 lug 2013 19:12:57

:) (non è che il default di WordPress sia sbagliato, eh?)

webaware webaware
31 lug 2013 03:19:50

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

Otto Otto
31 lug 2013 17:47:52

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.

webaware webaware
1 ago 2013 04:02:58

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 Otto
19 mar 2014 07:20:35
Mostra i restanti 4 commenti
2
20

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.

2 dic 2011 21:43:05
Commenti

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 :)

onetrickpony onetrickpony
2 dic 2011 22:39:26

@onetrickpony ecco perché è importante prendersi sempre il tempo necessario e fare le cose per bene, che tu ti aspetti che diventi grande un giorno oppure no :)

Mahmoud Al-Qudsi Mahmoud Al-Qudsi
12 dic 2017 01:16:23