Sunt tranzienții colectați automat ca gunoi?

9 ian. 2011, 02:20:17
Vizualizări: 35K
Voturi: 69

Această întrebare mi-a venit în minte după ce am văzut Feed-urile RSS tranziente din wp_options nu sunt eliminate automat?

Tranzienții ar trebui să expire și să fie șterși. Cu toate acestea, singura modalitate în care văd că acest lucru este gestionat este atunci când un tranzient este expirat și este solicitat, apoi este șters în timpul cererii.

Ce se întâmplă dacă un tranzient este expirat dar nu mai este solicitat după aceea? Din descrierea din Codex am crezut că există un fel de colectare automată a gunoiului. Acum nu mai sunt așa sigur și nu pot găsi niciun cod care să efectueze acest lucru.

Deci va rămâne blocat în baza de date pentru totdeauna?

25
Comentarii

teoretic, ar trebui să fie eliminate atunci când cron rulează (dacă au expirat)

onetrickpony onetrickpony
9 ian. 2011 02:34:01

@Ambitious Amoeba Nu văd nimic cu această funcționalitate legată de cron. De aceea întreb - pare a fi o presupunere de care nu sunt sigur că este validă.

Rarst Rarst
9 ian. 2011 02:37:59

Din câte înțeleg, transient-ele nu sunt chiar procese cron reale, ele necesită cel puțin ca cineva să solicite o pagină pentru a fi create/eliminate (dar reprezintă cea mai bună alternativă la un proces cron real). Nu am monitorizat transient-ele mele, observi că transient-ele rămân adesea după expirare?

t31os t31os
9 ian. 2011 18:35:47

@t31os da, le văd agățate, dar nu am informații despre cât timp pot rămâne agățate înainte să se poată spune cu siguranță că nu sunt colectate la gunoi

Rarst Rarst
9 ian. 2011 18:38:59

@Rarst - Nici eu nu sunt sigur cum este determinat curățarea, întâmpini această problemă cu anumite transiente sau cu unele diferite?

t31os t31os
9 ian. 2011 18:46:09

@t31os Nu am de gând să-mi pierd timpul codând un mecanism de înregistrare a transientelor înainte de a ști dacă ele ar trebui să fie colectate la gunoi deloc. :)

Rarst Rarst
9 ian. 2011 18:58:46

@Rarst - Nu am idee, prietene, voiam doar să împărtășesc câteva gânduri.. :)

t31os t31os
9 ian. 2011 19:11:06

se pare că transient-urile expirate sunt șterse când get_transient este apelat - http://core.trac.wordpress.org/browser/tags/3.0.4/wp-includes/functions.php#L721

onetrickpony onetrickpony
9 ian. 2011 19:11:44

Deci nu ar trebui să vezi niciun transient expirat în baza de date, decât dacă ceva nu a funcționat corect cu delete_option()

onetrickpony onetrickpony
9 ian. 2011 19:13:18

@Ambitious Amoeba da, am menționat asta într-o oarecare măsură în întrebare. Ideea mea este - crearea unui transient nu presupune sau garantează că acesta va fi vreodată solicitat. Subliniind întrebarea originală - când și dacă un transient expirat va fi șters dacă nu îl preiau niciodată?

Rarst Rarst
9 ian. 2011 19:17:47

dar care este rostul de a folosi transients atunci?

onetrickpony onetrickpony
9 ian. 2011 19:19:58

@Ambitious Amoeba ideea este că transients sunt un mecanism de caching. Conceptul de cache presupune date cu expirare și nu presupune accesări garantate. Dacă cache-ul nu curăță datele expirate, atunci are loc o scurgere de resurse.

Rarst Rarst
9 ian. 2011 19:29:23

presupune că ștergi datele expirate, dar da, ai dreptate, există situații în care acestea nu ar fi niciodată șterse. Cum ar fi eliminarea unui widget care folosește transient-uri. Ar trebui să depui un tichet pe trac pentru asta :)

onetrickpony onetrickpony
9 ian. 2011 19:36:11

@Rarst - Sună ca un lucru perfect pentru a scrie un patch și a-l trimite pe trac?

MikeSchinkel MikeSchinkel
9 ian. 2011 20:46:39

@MikeSchinkel daaaa... după ce cineva răspunde în sfârșit categoric dacă blestematele transient-uri sunt (sau ar trebui să fie) colectate ca gunoi :)

Rarst Rarst
9 ian. 2011 21:01:55

@Rarst - Singura modalitate de a fi sigur este să urmărești codul...

MikeSchinkel MikeSchinkel
10 ian. 2011 05:29:29

Nu este nevoie să fie "garbage collected". Dacă nu le accesezi niciodată, atunci nu contează dacă sunt acolo sau nu.

Otto Otto
12 sept. 2011 05:51:55

@Otto dacă începi să ai zeci de mii de astfel de intrări inutile în tabela de opțiuni (ceea ce se poate întâmpla și se întâmplă în practică, vezi întrebarea legată) cred că contează destul de mult, nu?

Rarst Rarst
12 sept. 2011 11:12:09

Nu, chiar nu. Bazele de date pot avea milioane și milioane de rânduri fără încetiniri apreciabile. Acest lucru se numește "indexare" și rămâne extrem de rapid chiar și cu foarte multe rânduri: http://en.wikipedia.org/wiki/Index_(database).

Mai mult, apelarea SQL DELETE asupra lor nu le șterge efectiv din baza de date. Doar le elimină din index, până când nu efectuați și o operațiune OPTIMIZE TABLE, care este o operațiune de durată. În general, nu este nevoie să "curățați" înregistrările dintr-o bază de date. Lăsați baza de date să-și facă treaba. E mai bună la asta decât dumneavoastră.

Otto Otto
12 sept. 2011 12:11:48

Ca să fiu mai specific, s-ar putea să observați că transientii din baza de date au flag-ul autoload setat pe "no", ceea ce înseamnă că nu se încarcă la pornire. Principala încetinire a oricărei interogări de bază de date este transferul efectiv al datelor din baza de date către program. Interogările în sine, dacă sunt scrise corect și indexate corespunzător (adică interogarea nu provoacă un scan de tabel), iau practic deloc timp în comparație. Nu contează dacă aveți 100 de înregistrări sau 100.000, deoarece efectuarea unui simplu SELECT pe un câmp indexat este o operațiune O(log(n)). Acest lucru nu se schimbă cu adevărat până când nu ajungeți la peste 1M+ de înregistrări.

Otto Otto
12 sept. 2011 12:26:28

@Otto Poți să muti asta într-un răspuns ca informația să fie mai vizibilă? Nu susțin că va fi nevoie de o mulțime de intrări inutile pentru a strica lucrurile... Dar dacă ceva scurgere resurse (ceea ce se întâmplă ușor cu transientii pentru că au o limită de lungime a cheii care nu este verificată, ușor de generat o grămadă din ele și să nu le mai atingi niciodată pentru că cheia este stricată) atunci mai devreme sau mai târziu va strica lucrurile. Nu țip "repara asta în nucleu", dar nici nu consider curățarea ca fiind inutilă.

Rarst Rarst
12 sept. 2011 12:36:39

"A strica lucrurile" este o afirmație destul de vagă. Cel mai rău lucru care se poate întâmpla este ca baza de date să devină prea mare pentru un spațiu limitat al contului. Nu va strica efectiv nimic până nu devine foarte, foarte mare. Lucrez cu tabele care au 20 de milioane de înregistrări. Căutarea în ele este un pic lentă, dar nu exagerat. Ai dreptate referitor la limita lungimii cheii, dar 45 de caractere sunt suficiente pentru orice caz realist la care mă pot gândi. Bineînțeles, este posibil să faci ceva nebunesc, dar se întâmplă asta des? Pare că ar trebui să fie notificat autorul plugin-ului în loc să se caute o soluție alternativă...

Otto Otto
12 sept. 2011 20:54:56

@Otto "nu des" și "niciodată" sunt lucruri diferite. Dacă voi face un plugin din asta, plănuiesc să adaug și un avertisment pentru lungimea cheii. Totuși, nu văd rostul păstrării datelor inutile în baza de date doar pentru că transient funcționează așa. Poate nu este o eroare, dar cu siguranță nu este o funcționalitate.

Rarst Rarst
12 sept. 2011 21:12:59

Ideea mea nu este să le păstrăm în baza de date doar pentru că funcționează așa. Ideea este că încercarea de a le "colecta ca gunoi" costă mai mult decât economisește, în aproape toate cazurile. De fapt, este contraproductiv.

Otto Otto
12 sept. 2011 21:33:04

Tichetul Trac asociat: http://core.trac.wordpress.org/ticket/20316

Stephen Harris Stephen Harris
30 sept. 2013 00:19:32
Arată celelalte 20 comentarii
Toate răspunsurile la întrebare 3
11
53

Acum sunt

Începând cu WordPress 3.7, transient-urile expirate sunt șterse la actualizarea bazei de date, vezi #20316


Răspuns vechi

Dacă cineva nu-mi poate demonstra contrariul, se pare că transient-urile nu sunt colectate ca gunoi după expirare. Ceea ce înrăutățește situația este faptul că, spre deosebire de opțiuni, ele nu sunt garantate a fi stocate în baza de date. Deci nu există o metodă sigură de a obține o listă cu toate transient-urile pentru a le verifica expirarea.

Un cod improvizat pentru a face colectarea gunoiului dacă baza de date este folosită pentru stocare:

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 ian. 2011 11:55:47
Comentarii

$time = $_SERVER['REQUEST_TIME']; și apoi utilizarea lui $time în interogarea SQL - nu face asta. Manipulează cu mai multă grijă variabilele / valorile $_SERVER pentru a preveni injecțiile SQL.

hakre hakre
10 ian. 2011 14:01:55

@hakre hm... Am luat asta dintr-o prezentare despre performanța PHP care o recomanda în locul folosirii time() care poate cauza bug-uri (execuția nu este instantanee prin natura sa). Timpul cererii este setat de PHP însuși, nu provine din nicio sursă de date furnizată de utilizator. De ce este aceasta o vulnerabilitate?

Rarst Rarst
10 ian. 2011 14:08:39

@Rarst: Nu am spus că nu ar trebui să-l folosești, ci doar să te asiguri că este codificat în siguranță pentru a fi utilizat în interogarea SQL. Ar trebui să faci asta cu fiecare variabilă dintr-o sursă externă. Variabilele $_SERVER ar putea să nu fie setate conform așteptărilor, și în schimb, să fie setate chiar de către utilizatorul care face cererea. Voiam doar să propag o bună practică de codare. Ca întotdeauna, pentru a afla starea reală a disponibilității, consultă documentația. Pentru PHP 4, de exemplu, o astfel de variabilă nu există și ar putea fi suprascrisă de un antet personalizat sau o variabilă de mediu - http://php.net/manual/en/reserved.variables.server.php

hakre hakre
10 ian. 2011 14:12:14

@hakre reparat (cred), mulțumesc pentru amintirea despre PHP4 (abia aștept ca WordPress să renunțe la suportul pentru el)

Rarst Rarst
10 ian. 2011 14:19:14

Arată mult mai bine în ochii mei ;). Să sperăm că nu vor fi probleme cu time() și numerele negative care ar putea șterge toate sau niciun transient din greșeală. Niciodată să nu ai încredere într-un sistem care funcționează :P

hakre hakre
10 ian. 2011 14:26:37

În caz că nu știai, _ este un wildcard de un singur caracter pentru instrucțiunile LIKE și ar trebui ideal să fie escap-at. :)

Denis de Bernardy Denis de Bernardy
10 ian. 2011 15:42:05

@Denis da, știu asta... Dar nicio diferență practică în această interogare?.. Doar dacă cineva reușește să denumească opțiunea XtransientXtimeoutX sau ceva de genul.

Rarst Rarst
10 ian. 2011 16:35:31

Nu ai folosi $wpdb->prepare() pentru a te proteja corespunzător de date suspecte, cum menționa @hakre? Acest lucru ar rezolva și escaparea caracterului '_'. Aș recomanda utilizarea lui, ca o practică bună.

Tom Auger Tom Auger
22 iun. 2012 04:31:21

@Tom în afară de "a fi extrem de sigur", această interogare specifică nu are nevoie cu adevărat de prepare și nu m-am obosit să o adaug.

Rarst Rarst
22 iun. 2012 11:35:16

Ai dreptate, acum când mă uit. Probabil că (int) este singura protecție de care ai nevoie pentru acea variabilă de server.

Tom Auger Tom Auger
22 iun. 2012 20:24:37

Nu ar trebui să fie _transient_timeout_%? Doar ca să fii sigur că acesta este într-adevăr prefixul folosit de WP? ;)

kaiser kaiser
28 iul. 2013 18:04:54
Arată celelalte 6 comentarii
9
21

Mutând unele dintre comentariile din discuție într-un răspuns, cu reformulare și reformatare...

Practic, se rezumă la faptul că, dacă nu ai un caz extrem de special, acestea nu trebuie neapărat „curățate”. Dacă nu le accesezi niciodată, atunci nu contează dacă sunt acolo sau nu.

Vezi, implicit, transient-urile sunt stocate în tabelul de opțiuni. Într-o instalare standard, tabelul de opțiuni poate avea aproximativ 100 de intrări. Fiecare transient adaugă două intrări suplimentare, dar chiar dacă ai mii, acestea nu afectează viteza site-ului, deoarece nu sunt încărcate automat.

La pornire, WordPress încarcă opțiunile în memorie, dar doar pe cele care au flag-ul de autoload activat. Transient-urile nu au acest flag, așa că nu sunt încărcate în memorie. Doar transient-urile care sunt efectiv utilizate ulterior vor implica un cost.

Din perspectiva bazei de date, tabelul de opțiuni are indexuri atât pe ID-ul opțiunii, cât și pe numele opțiunii. Transient-urile sunt întotdeauna încărcate pe baza numelui (cheii), așa că căutările pentru ele sunt întotdeauna select-uri simple pe o singură valoare de cheie unică. Astfel, căutarea este O(log(n)) și este extrem de rapidă. Cu o complexitate de log(n), ar trebui să ajungi la milioane și milioane de rânduri înainte să devină observabil. Sincer, overhead-ul în configurarea și finalizarea interogării, împreună cu transferul efectiv de date, este mult mai lung. Interogarea în sine rulează în timp practic zero în comparație. Deci simplul fapt de a avea rânduri neutilizate nu afectează nimic, în afară de utilizarea unui spațiu suplimentar pe disc.

Indexarea în bazele de date este una dintre acele idei complexe care nu au sens pentru cei care nu au înțeles ce se întâmplă în spate. Bazele de date sunt concepute pentru recuperarea rapidă a datelor, de la bază, și pot gestiona acest tip de lucruri fără probleme. Acesta este un material destul de bun: http://en.wikipedia.org/wiki/Index_(database)

Acum, curățarea în modul cel mai evident (apelând SQL DELETE pe ele) nu le șterge efectiv din baza de date. Doar le elimină din index și marchează rândul ca „șters”. Din nou, așa funcționează bazele de date. Pentru a elibera efectiv spațiul pe disc, trebuie să continui cu un OPTIMIZE TABLE după aceea, iar aceasta nu este o operație rapidă. Durează timp. Probabil mai mult decât merită. Probabil nu este suficient pentru a economisi timp CPU, în total.

Dacă ai un caz care provoacă o inserare continuă de transient-uri noi care nu sunt utilizate, atunci trebuie să găsești problema de bază. Ce inserează aceste transient-uri? Folosesc o cheie care se schimbă sau se modifică? Dacă da, atunci plugin-ul sau codul care provoacă acest lucru ar trebui reparat pentru a, practic, nu mai face asta. Asta va fi mai util, pentru că e probabil ca codul care le creează necorespunzător să nu le și recupereze, făcând astfel mai multă muncă decât ar trebui.

Pe de altă parte, poate exista un caz în care transient-urile sunt create pentru ceva precum fiecare articol. Acest lucru poate fi perfect acceptabil. Eu fac asta în SFC, pentru a stoca comentariile primite de pe Facebook. Fiecare articol are un potențial transient asociat, ceea ce înseamnă două rânduri suplimentare per articol. Dacă ai 10k articole, vei avea 20k rânduri în tabelul de opțiuni (eventual). Nu este rău sau lent, pentru că, din nou, diferența dintre 100 de rânduri și 20.000 de rânduri este foarte mică din punctul de vedere al bazelor de date. Totul este indexat. Este extrem de rapid. Sub-sub-milisecunde.

Când începi să ajungi la milioane de rânduri, atunci aș fi îngrijorat. Când dimensiunea tabelului de opțiuni depășește sute de megaocteți, atunci aș fi îngrijorat suficient pentru a arunca o privire mai atentă. Dar, în general, aceasta nu este o problemă, cu excepția cazurilor extreme. Cu siguranță nu este o problemă pentru orice mai mic decât un site de știri mari, cu sute de mii de articole. Și pentru orice site suficient de mare pentru a fi o problemă, ar trebui să folosești un cache extern de obiecte, iar în acest caz, transient-urile sunt stocate automat acolo în loc de în baza de date.

12 sept. 2011 21:09:10
Comentarii

Notă: transient-urile fără termen de expirare sunt încărcate automat, iar absența unui termen de expirare este implicită, așadar atunci când o aplicație/un plugin creează multe transient-uri fără a seta un termen de expirare, acestea vor ocupa porțiuni de memorie la fiecare încărcare de pagină/postare.

webaware webaware
29 iul. 2013 03:48:50

Nu există niciun motiv să folosești un "transient fără termen de expirare", deoarece acesta este practic identic cu o "opțiune" normală.

Otto Otto
30 iul. 2013 02:43:05

Desigur, dar aceasta este valoarea implicită. Ca urmare, mulți autori de plugin-uri adaugă transient-uri fără termen de expirare.

webaware webaware
30 iul. 2013 03:19:35

De asemenea, nu este identic cu o opțiune, deoarece va fi eliminat când se utilizează un cache de obiecte -- vezi articolul recent pe WPEngine pentru detalii.

webaware webaware
30 iul. 2013 03:21:32

Ei bine, soluția aici este simplă: Nu folosi acele plugin-uri. Ele fac lucrurile greșit. Tranzientele nu trebuie folosite ca sesiuni, nu ar trebui să le folosiți fără o expirare semnificativă și nu ar trebui să aibă chei care se modifică sau se schimbă.

Otto Otto
30 iul. 2013 19:12:57

:) (pentru că nu este pentru că setarea implicită din WordPress este greșită, nu-i așa?)

webaware webaware
31 iul. 2013 03:19:50

Depinde. Ce valoare implicită consideri rezonabilă acolo în schimb?

Otto Otto
31 iul. 2013 17:47:52

Să zicem, 7 zile. Dacă un autor de plugin/temă vrea ceva mai mare sau mai mic, îl va specifica. Dacă vor autoload, nu ar trebui să fie nevoie să specifice 0 pentru expirare (= infinit), dar asta e ce au acum cu parametrul de expirare care face dublu rol ca parametru da/nu pentru autoload. În orice caz, expirarea implicită nu ar trebui să ducă și la autoload=da ca valoare implicită; asta e doar o invitație la probleme.

webaware webaware
1 aug. 2013 04:02:58

În opinia mea bine chibzuită, ne-specificarea unei expirări ar trebui să arunce o eroare fatală și să rupă site-ul. Dar, ei bine, nu eu sunt la cârmă. Un transient fără expirare este stupid și fără sens. Dacă vrei să folosești cache-ul de obiecte, atunci folosește direct cache-ul de obiecte cu funcțiile wp_cache. Cu toate acestea, există tichete pentru a avea versiuni viitoare de WordPress care să curețe tranșientele vechi, mai mult pentru că sunt "inestetice" decât pentru orice alt motiv.

Otto Otto
19 mar. 2014 07:20:35
Arată celelalte 4 comentarii
2
20

Otto - Nu pot să fiu mai în dezacord cu tine. Problema este că, în cele din urmă, cu toate acele transient-uri, dimensiunea tabelului devine ridicolă. Nu sunt necesare milioane de rânduri pentru a încetini lucrurile. În prezent mă confrunt cu un tabel de opțiuni care are peste 130k de rânduri și se blochează regulat. Deoarece câmpul `value` este de tip text lung, chiar și căutarea doar a rândurilor cu "autoload" devine un coșmar din punct de vedere al performanței. Acele câmpuri value sunt stocate separat de restul datelor din rând. Chiar dacă din punct de vedere logic fac parte din același tabel, trebuie să se facă join-uri pentru a obține rândurile dorite. Join-uri care acum durează o eternitate deoarece datele de care ai nevoie sunt împrăștiate peste tot pe disc. Profilarea (folosind Jet Profiler pentru MySQL) a demonstrat acest lucru.

Adăugarea auto-load la cheia clustered ar putea ajuta la rezolvarea acestei probleme. Clustered pe Autoload Desc, ID ASC de exemplu, ar permite tuturor rândurilor autoload să se grupeze împreună mai întâi pe disc. Totuși, cred că tot ai o încărcare uriașă din perspectiva bazei de date.

Personal, cred că designul acestui sistem este prost. Tabelul de opțiuni pare să fi devenit un loc de depozitare generală pentru multe lucruri. Asta e ok dacă câmpul value este suficient de mic pentru a fi inclus pe aceeași pagină cu restul datelor din rând și poate fi indexat eficient. Din păcate, nu este cazul. Cine a proiectat asta trebuie să revină la cursul de Baze de Date 101.

2 dec. 2011 21:43:05
Comentarii

adevărat, dar ia în considerare faptul că atunci când a început dezvoltarea WordPress, nimeni nu s-a gândit că va ajunge să aibă mii de plugin-uri care folosesc tabelul de opțiuni ca stocare de date :)

onetrickpony onetrickpony
2 dec. 2011 22:39:26

@onetrickpony de aceea este important să-ți iei întotdeauna timp și să faci lucrurile corect, indiferent dacă te aștepți să devină enorme într-o zi sau nu :)

Mahmoud Al-Qudsi Mahmoud Al-Qudsi
12 dec. 2017 01:16:23