Despre cursoare explicite și implicite, dimensiuni și intervale de extensie

Tom Kite: Pe cursorii explicit și implicit,
dimensiunile extensiilor și intervale complexe
(Cu privire la Explicit, Dimensiune și Complex.) De Tom Kyte

Expertul nostru răspunde la întrebări despre cursoare, întinderi și intervale.

Întrebare: Este adevărat că începând cu Oracle7 Release 7.3, cursorii impliciți sunt optimizați și nu efectuează o dublă eșantionare? De asemenea, de ce următorul cursor implicit funcționează mai repede decât cursorul explicit prezentat mai jos, dacă tabelul T are un index pe coloana X, în caz contrar cursorul explicit funcționează mai repede?

Răspuns: Cursor implicit:

Voi începe cu o scurtă definiție, astfel încât toată lumea să înțeleagă ce sunt cursoare implicite și explicite.

În general, un cursor implicit este un cursor pe care programatorul "nu îl declară în mod explicit", îl deschide, îl selectează sau îl închide; aceste operațiuni sunt implicite. Deci, în exemplul de mai sus, interogarea SELECT X INTO Y este un cursor implicit. Pentru aceasta, nu există nici o definiție a cursorului "cursor_name is.". În al doilea exemplu, pe de altă parte, este afișat un cursor explicit clasic. Programatorul declară explicit, deschide, alege din ea și o închide.

Deci, cursoarele implicite în PL / SQL sunt mai rapide decât cursoarele explicite și sunt mai rapide înainte de lansarea Oracle7 Release 7.3. De fapt, am o suită de testare care arată că acesta este cazul cu baza de date Oracle7 Release 7.1 (a se vedea asktom.oracle.com/ pentru aceste teste

tkyte / ivse.html). Motivul pentru care cursoarele implicite mai rapid (ca implicite cicluri cursoare Cursorul și cursoare implicite în situațiile SELECT INTO), constă în faptul că, în acest caz, PL / mașină de SQL este necesar pentru a interpreta și executa mult mai puțin de cod. În general, cu cât mai mult codul PL / SQL poate fi "ascuns", cu atât mai repede va funcționa. Pentru cursorul implicit arătat mai sus, este necesară o linie de cod PL / SQL; pentru un cursor explicit, sunt necesare cel puțin trei linii de cod, iar dacă ați făcut "corect", aveți nevoie de șase linii de cod. Codul dvs. explicit nu efectuează toate lucrările cursorului implicit, care verifică faptul că vi se garantează că veți obține o singură linie. Codul dvs. explicit nu are multe din ceea ce trebuie să faceți. Pentru a compara cu exactitate cele două cursoare de exemplu, codul dvs. explicit trebuie să aibă mai multe linii:

Dacă a fost cursorul dvs. explicit, ați descoperi că cursorul explicit este mai lent în toate cazurile, chiar și în exemplul dvs. cu sau fără un index.

Am creat o masă cu multe blocuri; Aceasta se face prin setarea parametrului pctfree 99, care rezervă 99% din spațiul blocului pentru actualizările ulterioare ale blocurilor ("spațiu liber"). Deci, chiar dacă cantitatea de date din tabel este mică, masa însăși este destul de mare. În plus, am introdus în tabel valorile 1, 2, 3. până la 29 264 plasate în mare măsură în ordine. Deci, valoarea X = 1 este în blocul "first" al tabelului, iar valoarea X = 29,000 este suficient de aproape de ultimul bloc al tabelului.

Acest lucru explică comportamentul cursorilor dvs .: instrucțiunea SELECT INTO verifică oa doua linie, în timp ce cursorul dvs. explicit nu o face. Dacă comparați merele cu mere - sau faceți oa doua selecție explicită sau adăugați predicatul "rownum = 1" la instrucțiunea SELECT INTO - veți observa că ambii cursori efectuează aceeași cantitate de lucru.

Întrebare: Pentru noua noastră aplicație, am creat o bază de date și am creat un model de date. Am setat chiar dimensiunea tabelelor și am definit parametrii de stocare pentru fiecare tabel. Dar acum specialiști în administrația noastră bază de date ne spune că ei ne vor oferi trei spații de tabelă: TS_small (spațiu tabelă este mic) din aceeași măsură dimensiunea de 160 KB, TS_med (spațiu tabelă este o mărime medie), cu aceeași măsură, dimensiunea la 5 MB , și TS_large (un spațiu de masă mare) cu aceeași dimensiune de 160 MB. Ei ne spun că este necesar să se creeze tabele, a căror dimensiune este mai mică de 5 MB în TS_small TABLESPACE, dimensiunea mesei va fi mai mică de 160 MB, TS_med și tabele, dimensiunea, care va fi mai mare de 160 MB, TS_large. În plus, nu doresc ca noi să folosim parametrii de stocare la nivelul mesei. Ei spun că același lucru ar trebui să fie pentru indicii. Nu pare rezonabil pentru mine, pentru că o masă cu o dimensiune estimată de 120 MB, trebuie să fie plasat într-un spațiu tabelă TS_med, iar acest lucru va dura 24 de măsură! Administratorii de baze de date susțin că numeroase teste au demonstrat că un astfel de design oferă cele mai bune performanțe și împiedică fragmentarea. Întrebarea mea este: au dreptate? Sunt îngrijorat de obiecte atât de multe.

Răspuns: Ei bine, se pare că au citit site-ul "Ask Tom" (asktom.oracle.com) și conținutul grupurilor de interese de pe Internet și a găsit o recomandare bună. Privind numerele lor, văd că o masă de până la 5 GB va avea 32 de dimensiuni sau mai puține. Având în vedere că sute (sau chiar mai multe) extensii nu vor afecta performanța declarațiilor LMD, aș spune că au făcut o treabă excelentă.

Ambele ipoteze sunt corecte: fragmentarea spațiilor de tabel va fi imposibilă, iar performanța va fi optimă. Să ne uităm la fiecare declarație.

Faptul că fragmentarea este imposibilă este ușor de verificat. Un spațiu de tabelă gestionat folosind un spațiu de tabele gestionat de dicționar este fragmentat datorită extensiilor de dimensiuni diferite. Un spațiu de tabel gestionat utilizând un dicționar de date poate avea mii de extensii care sunt libere și utilizate, fiecare dintre ele putând avea o dimensiune diferită. Acum începeți să distrugeți și să creați obiecte în acest spațiu de tabel și în timp aveți în el un număr mare de "găuri" de diferite dimensiuni (spațiu liber). Așadar, puteți verifica spațiul de tabelă gestionat de dicționarul de date și puteți determina dimensiunea spațiului liber din acesta, descoperind 500 MB gratuit. Dar când încercați să creați un tabel cu dimensiunea inițială egală cu 40 MB, veți obține o eroare - este imposibil să alocați prima măsură. Cum s-ar putea întâmpla asta? Aveți 500 de MB gratuit, nu? Da, bine, dar, din păcate, aceste 500 MB sunt într-o mulțime de dimensiuni, fiecare dintre ele având o dimensiune mai mică de 40 MB! Deci, aveți o mulțime de spațiu liber inutil - spațiul dvs. de tabel este fragmentat. Acum, luați în considerare un spațiu de tabel gestionat local, cu dimensiuni de aceeași dimensiune. Aici, fiecare măsură are aceeași dimensiune ca toate celelalte extensii, fără excepție. Dacă găsiți că aveți 500 de MB liber, vă pot asigura că veți putea aloca o nouă dimensiune în acest spațiu de tabel, deoarece fiecare extindere liberă poate fi utilizată prin definiție pentru obiectul dvs.

tkyte / extents.html și asktom.oracle.com/

tkyte / extents2.html. în fiecare dintre acestea există o discuție destul de lungă pe această temă. Treizeci și două de extensii pentru obiectele dvs. sunt excelente, nu va fi niciun impact asupra performanței. De fapt, deoarece spațiile de tabel gestionate local sunt mult mai eficiente în alocarea spațiului decât spațiile de tabel gestionate folosind un dicționar de date, utilizarea acestora va crește productivitatea și nu invers.

Întrebare: Folosesc pachetul DBMS_JOB și doresc să programez lansarea sarcinilor la fiecare 15 minute de luni până vineri, începând cu ora 6:00 dimineața până la ora 6:00 seara. Cum se poate face acest lucru? Nu pot calcula intervalul trecut la pachet.

Răspuns: Ei bine, pentru a calcula intervale complexe pentru pachetul DBMS_JOB, îmi place să folosesc instrucțiunea nouă (de la lansarea Oracle8i Release 2) CASE. De exemplu, următoarea instrucțiune CASE returnează intervalul corect pentru caietul de sarcini:

Instrucțiunea CASE oferă mai multă flexibilitate atunci când generează valoarea complexă de care aveți nevoie. Din păcate, pachetul DBMS_JOB vă permite să utilizați numai astfel de intervale, lungimea cărora nu depășește 200 de caractere și chiar dacă comprimați operatorul de mai sus, veți observa că lungimea sa este aproximativ egală cu cel puțin 300 de caractere. Deci, nu îl puteți folosi direct în pachetul de pachete DBMS_JOB. Soluția mea este următoarea: Sau aș crea o vizualizare NEXT_DATE astfel încât operatorul select de la next_date să revină la următoarea executare a lucrării sau să implementez instrucțiunea de mai sus într-o funcție PL / SQL care returnează o dată. Dacă am folosit o vizualizare, apelul meu la pachetul DBMS_JOB ar putea să arate cam așa: /

Întrebare: Avem mai multe tabele, secționate după timp (anul fiscal). Ce recomandați, ca o abordare mai bună, de a avea acces la date istorice în modul read-only și la accesul la datele curente în modul citire-scriere?

Răspuns: într-adevăr, acest lucru este destul de ușor pentru a realiza. Spațiul de tabelă poate fi în modul read-only sau în modul citire-scriere. Dacă utilizați un spațiu tabelă separat pentru fiecare partiție (sau cel puțin să păstreze secțiunea istorică într-un spațiu tabelă separat decât cel actual), trebuie să facă disponibil doar în „read-only“, puteți executa pur și simplu un TABLESPACE ALTER <имя табличного пространства> CITIȚI NUMAI. Utilizatorii finali nu pot modifica spațiul de tabelă, și, de fapt, puteți salva o cantitate semnificativă de timp petrecut pe rezerva, pentru că va trebui să creați o copie de rezervă o dată (cu excepția cazului în care nu pune-l în modul de „citire-scriere“ și modificați acesta, în acest caz, vă, desigur, ar trebui să creați din nou copia de rezervă).

De fapt, puteți chiar să mutați acest spațiu de tabelă în medii numai pentru citire, cum ar fi CD-uri, care împiedică modificarea acestuia.

Întrebare: Explicați, vă rog, ce sunt apelurile recursive, db block gets, etc.

Serverul Oracle acceptă tabelele utilizate pentru operațiile interne. Dacă serverul Oracle are nevoie să schimbe aceste tabele, atunci o instrucțiune SQL este generată în sistem, ceea ce la rândul său generează apeluri recursive.

Pe scurt, apelurile recursive sunt în esență instrucțiuni SQL executate în numele instrucțiunii dvs. SQL. De exemplu, dacă ați analiza interogarea, ar putea fi necesar să rulați alte interogări pentru a obține informații din dicționarul de date. Ar fi vorba de apeluri recursive. Gestionarea spațiului, verificarea regulilor de control al accesului, apelarea procedurilor PL / SQL din instrucțiunile SQL conduc la apeluri recursive.

  • DB Block Gets (citirea blocurilor bazei de date). Numărul de blocuri primite în modul CURRENT.

CITIȚI documentația Oracle9i:
Oracle9i Ghid de referință pentru performanța bazei de date și referință
otn.oracle.com/docs/products/oracle9i/
doc_library / release2 / server.920 / a96533 / autotrac.htm # 14931

ASCULT VOLUMUL
asktom.oracle.com
Tom Kite - vicepreședinte al grupului Oracle Government, Education and Health - răspunde la cele mai dificile întrebări legate de tehnologia bazei de date Oracle. Cele mai vii materiale ale acestui forum sunt publicate în această coloană.

LEARN Cursoare:
asktom.oracle.com/

  • Consistentă obținerea de câte ori a fost solicitat un bloc pentru a efectua operațiuni numai citite.

Practic, aceasta va fi dimensiunea cumulativă a setului de rezultate.

  • Bytes primite prin SQL * Net din Client (octeți primite de la client prin SQL * Net). Numărul total de octeți primite de la client în rețea.

Practic, aceasta este dimensiunea solicitării dvs., în forma în care este transmisă prin rețea

  • SQL * Net Roundtrips către / de la Client (schimburi reciproce prin SQL * Net cu clientul). Numărul total de mesaje de rețea trimise sau primite de la client.

Practic, acesta este numărul de interacțiuni cu serverul pentru a obține răspunsul. Odată ce creșteți valoarea variabilei sistemului ARRAYSIZE în SQL * Plus, veți vedea că acest număr pentru instrucțiunile SELECT care returnează mai multe rânduri scade (mai puține schimburi reciproce, deoarece fiecare extras din liniile N este un schimb reciproc). Când scade valoarea ARRAYSIZE, veți vedea că acest număr crește.

  • Sortați (memorie). Numărul operațiilor de sortare care au fost executate complet în memoria RAM și nu necesită scrierea pe disc.

Nu poți face mult mai bine decât sortarea în memorie, poate doar prin excluderea sorții. Sorburile apar în mod obișnuit în timpul executării interogărilor care, în specificarea condițiilor eșantionului, conțin operațiile de îmbinare a tabelelor.

  • Sortați (disc). Numărul operațiilor de sortare care necesită cel puțin o înregistrare pe disc. Sortimentele care necesită I / O pe disc consumă intens resurse. Încercați să creșteți valoarea parametrului de inițializare SORT_AREA_SIZE.
  • Rândurile procesate (rândurile procesate). Numărul total de rânduri returnate de instrucțiunea dvs. SELECT sau modificate printr-o instrucțiune INSERT, UPDATE sau DELETE.