Codificare eficientă pe pl

Arup Nanda, membru-director al Oracle ACE

Declanșatoare care foc de mai multe ori, în funcție de eveniment, capacitatea de a specifica declanșează un tip de secvență de funcționare, noua propunere CONTINUA - aici sunt unele dintre noile caracteristici care simplifică programarea cu PL / SQL.







De la început, PL / SQL a fost limba aleasă pentru programarea în Oracle Database. După un timp, a devenit evident că, datorită funcționalității crescânde, care necesită mai puțină codificare, limba sa dezvoltat într-un grad suficient pentru a fi pe deplin dezvoltat. Oracle Database 11g face codificarea pe PL / SQL chiar mai eficientă pentru programatori. În acest articol, vom examina câteva exemple care vă vor permite să vă familiarizați pe scurt cu noile funcționalități.

Luați în considerare baza de date a hotelului: jurnalele camerelor de hotel sunt stocate în tabelul REZERVĂRI. De asemenea, trebuie să scrieți modificări în acest tabel pentru controlul său - ceva de genul unui audit, dar cu o particularitate: trebuie să o faceți tranzacțional. Declanșatoarele sunt cele mai bune pentru acest lucru.

Aceasta necesită un declanșator mic pentru evenimentul ulterior actualizării pentru un șir care scrie valorile vechi și noi în tabelul BOOKINGS_HIST, precum și persoana care a efectuat modificarea. Până acum, atât de bine.

Există totuși o mică problemă. După declanșarea unui rând de actualizare este declanșat pentru fiecare rând, iar unele înregistrări se modifică în ordine de masă, schimbând sute de rânduri pe tranzacție. Declansarea individuală a declanșatorului de rând după actualizare pentru fiecare rând și executarea fiecărei inserări a intrării în tabelul bookings_hist fac ca performanța să nu fie optimă.

Ar fi mai bine să punem împreună aceste inserturi în tabelul bookings_hist și să le executăm o grămadă. Acest lucru se poate face printr-o serie complexă de declanșatoare. Concluzia este că ar trebui să punem valorile destinate bookings_hist tabelul în colecția din declanșator pe fiecare scurgere, iar apoi încărcați datele din colecția în bookings_hist tabelă folosind declanșare după actualizare pentru a oferi, care se declanșează o singură dată. Întrucât, de fapt, inserarea are loc doar o singură dată, procesul se execută mai repede decât introducerea fiecărui rând individual.

Dar acestea sunt două declanșatoare diferite cu coduri diferite. Există doar o singură cale de a trece o variabilă la o colecție de un flip-flop în cealaltă - pentru a crea un pachet cu o variabilă de colectare, cum ar fi o matrice sau un / SQL-tabel PL în caietul de sarcini pachet, completați-l în declanșatorul linia după actualizare și citit în după declanșare oferta - și aceasta nu este o sarcină ușoară. Nu ar fi mai simplu să punem toți declanșatorii într-un singur cod?

În Oracle Database 11 g, puteți utiliza declanșatoare compuse. Triggerii compușilor sunt patru declanșatoare diferite, declarate ca una. De exemplu, un trigger compus UPDATE are înainte pentru o propoziție, înainte pentru un șir, după o propoziție și după o șir care sunt simultan prezente într-un trigger compus. Aici este o parte a codului care descrie modul în care puteți trece variabilele ca în interiorul unui cod PL / SQL monolitic.

Să luăm în considerare un exemplu. Numerele de linie sunt adăugate pentru a facilita explicația.

Pentru a înțelege mai bine funcționarea declanșatorului, efectuați o actualizare demonstrativă care modifică cele patru linii.

Observați cum se execută declanșatorul compozit. Are patru secțiuni:
Înainte de declarație
. se execută o dată înainte de propunere.
Înainte de Row
. se execută o dată pentru fiecare rând înainte de acțiunea însăși.
După Row
. se execută o dată pentru fiecare linie după acțiune.
După declarație
. se execută o singură dată pentru propunere.

După cum puteți vedea, acest cod este unul, dar fiecare secțiune este executată în momente diferite.

În exemplul anterior, am pus clauzele dbms_output în diferite locuri pentru a arăta modul în care fiecare secțiune este executată în aceste puncte. Am modificat cu booking_ids patru linii de 100, 101, 102 și 103, și se vede că declanșează și după fiecare inainte de a-lucrat pentru oferta o singură dată și declanșează linia (înainte și după) o dată pe linie. (În exemplul anterior, declanșatoarele de mai sus pentru teză și șir nu sunt necesare, dar le-am scris pentru a ilustra funcționalitatea).

Dacă te uiți la tabelul bookings_hist, poți vedea că există acum patru intrări în el - câte unul pentru fiecare booking_id - dar aceste patru intrări au fost inserate într-o grămadă la sfârșitul tezei, mai degrabă decât schimbând fiecare rând:

O caracteristică foarte utilă a declanșatorilor compuși este aceea că obiectele interne ale codului PL / SQL, cum ar fi variabilele, pachetele și așa mai departe. sunt create atunci când se declanșează declanșatorul, iar la sfârșitul operației de declanșare, starea lor este șters. În exemplul de mai sus, colecția nu a fost inițializată, iar conținutul colecției nu a fost șters. Toate acestea au fost făcute automat fără intervenția mea.

Secvența executării declanșatorilor

Începând cu Oracle8, a fost posibil să descriem mai multe declanșatoare de același tip pe o singură masă - de exemplu, două linii după declanșare atunci când sunt inserate într-un singur tabel. Tipul declanșatorilor determină ordinea execuției: înainte de propoziție, înainte de linie, după teză și după linie. Cu toate acestea, dacă există două post-declanșatoare de ordin inferior, T1 și T2, care dintre ele va funcționa mai întâi?

Rularea declanșatoare de același tip în mod arbitrar sau cel puțin neapărat urmează modelul. Este o problemă? Să examinăm un exemplu al tabelului PLĂȚI, prezentat mai jos:







Este necesar să calculați ratingul de risc în funcție de tipul de plată și de suma și să îl salvați în coloana RISK_RATING. Următorul simplu declanșator la nivel de linie înainte de actualizare gestionează cu ușurință această sarcină:

Acum, cineva adaugă încă o cerință. Unele valori în funcție de coloane RISK_RATING, PAY_MODE, etc ar trebui să fie FOLLOW_UP semn coloana marcată de creștere. Triggerul trebuie modificat, dar este mai bine să nu atingeți codul existent, ci să creați un nou declanșator de același tip (o linie înainte de actualizare), după cum se arată mai jos. (Am introdus dbms_output în cod pentru a arăta cum declanșează declanșatoarele).

Acum, dacă actualizați masa:

Ce sa întâmplat? coloană risk_rating este setat HIGH, și coloana pay_mode - valoarea „C“, ceea ce înseamnă că coloana trebuie să fie FOLLOW_UP „Y“, și nu „N“. De ce? Pentru a răspunde la această întrebare, uitați-vă la ordinea în care au declanșat declanșatoarele: tr_pay_follow_up a lucrat înainte de tr_pay_risk_rating. Acesta din urmă a stabilit valoarea coloanei ca pe un rating ridicat. Prin urmare, când a lucrat primul, a găsit nulă (sau "N") în coloana risk_rating și, prin urmare, a simțit că condiția a fost satisfăcută.

În acest caz, ordinea declanșatorilor este foarte importantă. Dacă tr_pay_risk_rating nu funcționează înainte de al doilea, valorile corecte nu vor fi setate și ceea ce este instalat va fi o implementare incorectă a cerințelor. Singura opțiune simplă ar fi înlocuirea întregii logici cu un singur cod și executarea acesteia în ordinea corectă.

În Oracle Database 11 g, puteți specifica o expresie în scriptul de declanșare care stabilește ordinea declanșatorilor. Aici este partea superioară a declanșatorului, care include această expresie:

Această expresie (FOLLOWS <название_триггера>) determină declanșarea declanșatorului după declanșarea specificată. Testează acest lucru rulând scriptul de actualizare afișat mai devreme.

După cum era de așteptat, coloana este completă corect. Rețineți și ordinea corectă a declanșatorilor, care confirmă faptul că expresia funcționează.
Ordinea declanșatorilor vă permite să profitați de codul modular, permițându-vă, de asemenea, să vă asigurați că acestea sunt executate în ordinea corectă.

Când nu este nimic de îndeplinit, executăm CONTINUE

Împreună cu toate capacitățile sale până în prezent, o parte importantă a gramaticii a fost ratată în PL / SQL: cum să arătați că nu trebuie să faceți nimic, dar trebuie să mergeți la sfârșitul bucla și să o continuați.

În Oracle Database 11g, PL / SQL are o nouă construcție CONTINUE utilizată în buclă. Această teză mută logica la sfârșitul bucla și apoi la începutul buclă. Iată un mic exemplu care arată modul în care controlul este trecut la sfârșitul unei buclă, atunci când contorul nu este un multiplu de 10.

O altă variantă a CONTINUE este utilizarea numelui ciclului.

În loc să utilizați o construcție predefinită, cum ar fi mod (interior, 3), puteți utiliza o funcție care efectuează unele calcule.

Nu este nevoie să spunem că acest design poate fi folosit numai în interiorul unei bucla unde are sens. Dacă încercați să-l utilizați în afara bucla, veți obține o eroare de compilare.

Când o secvență a fost folosită mai devreme în programul PL / SQL, trebuie să utilizați un SELECT <последовательность>.NEXTVAL INTO <название_переменной> De la DUAL până la această lansare.

Nu mai este necesar. Puteți atribui direct următoarea valoare variabilei:

Aceasta este ceea ce eu numesc simplitate.

Teza "Când ceilalți atunci" face orice

Mulți programatori PL / SQL recurg la practici periculoase, lăsând excepția OTHERS ignorată, după cum se arată mai jos:

Acest lucru spune despre următoarele: "Când apare o eroare, nu faceți nimic, ignorați sau pretindeți că acest lucru nu se va întâmpla niciodată și că nu se va mai întâmpla". Dacă lumea era atât de simplă! Această practică duce la un cod potențial eronat instabil.

Oracle Database 11g ajută un pic în această direcție. În el există o remarcă nouă PLW-06009, înștiințând despre o astfel de problemă la momentul compilării. Iată un exemplu:

La compilație, procedura este compilată fără observații, așa cum a fost în 10 g. Pentru a activa acest lucru, trebuie să setați parametrul sesiunii.

Rețineți că noua notă PLW-06009 apare la timpul de compilare. Și aceasta este doar o remarcă; întreaga compilație a avut succes. Puteți efectua procedura, dar țineți cont de remarca!

În Oracle Database 11g, acest script nu mai este o problemă. Puteți crea un declanșator care a fost inițial dezactivat, ceea ce vă permite să testați toate erorile de compilare. Și mai târziu, când editați, activați-o. Iată cum să creați unul:

Acum puteți verifica starea sa:

SQL> selectați starea
2> de la user_triggers
3> unde trigger_name = 'TR_T'
4> /

Chiar dacă declanșatorul a fost creat dezactivat, acesta trebuie să fie fără erori. Prin urmare, dacă încercați să o creați cu o eroare (de exemplu, folosind tabelul "M", care nu există):

Această funcție este foarte utilă în controlul modificărilor. O altă aplicație remarcabilă a acestei caracteristici este includerea declanșatorilor la un anumit moment. De exemplu, utilizând declanșatoarele, creați o soluție de audit și tabela de audit nu a fost eliminată din vechile înregistrări. Declanșatoarele pot fi create și activate mai târziu, când masa este gata.

Numiți parametrii funcției

Luați în considerare o funcție simplă:

Această funcție face o operație foarte simplă, dar demonstrează bine conceptul. Deoarece există două parametri în această funcție, puteți să o numiți prin trecerea parametrilor ca valori poziționale, și anume:

Sau ca parametri numiți:

Cu toate acestea, în final, există o problemă dacă o folosiți în propoziții selectate. Dacă executați următoarea declarație în Oracle Database 10g:

În Oracle Database 11 g, aveți dreptul să utilizați notația:

care funcționează corect. Puteți specifica o notație numită la sfârșit și primii parametri trebuie să fie poziționați. De exemplu, următorul apel, în cazul în care p_param1 este 1, este corect:

Și aceasta nu este (parametrul de poziție la sfârșit):

Interschimbabilitatea cursorului dinamic și a cursorului REF

Știți cât de util poate fi Cursorul Nativ Dynamic, mai ales atunci când nu știți exact ce va fi solicitat înainte de apel. Dynamic PL / SQL poate fi de asemenea utilizat prin intermediul DBMS_SQL. Ambele metode au avantajele lor. Dar ce se întâmplă dacă ați început să dezvoltați un program care folosește mai întâi o metodă și apoi trebuie să treceți la altul?

În Oracle Database 11 g, acest proces este neobișnuit de simplu. Pachetul suportat DBMS_SQL are o nouă funcție, TO_REFCURSOR, care convertește cursorul dinamic DBMS_SQL la un cursor ref. Iată un exemplu al unei astfel de conversii:

Să presupunem că doriți să scrieți o procedură generică care nu cunoaște lista de coloane din expresia selectată la momentul compilării. Acesta este cazul atunci când devine SQL dinamic nativ devine necesar. Puteți descrie cursorul ref pentru el. Acum, pentru a face mai interesant, să presupunem că nu cunoașteți toate variabilele de legare, dbms_sql este cel mai potrivit pentru acest caz. Cum să îndepliniți această cerință complexă prin scrierea unui minim de cod? Pur și simplu: începeți cu dbms_sql pentru variabilele de legare și apoi convertiți la cursor ref.

În mod similar, pentru a converti Native Dynamic SQL într-un cursor REF, trebuie să apelați o altă funcție, TO_CURSOR_NUMBER:

Cursorul ref definit în variabila c_ref_cur trebuie să fie deschis înaintea acestui apel. După acest apel, durata cursorului de referință a terminat; Puteți să manipulați numai cursorul dbms_sql.

Să presupunem că știți legături variabile la momentul compilării, dar nu știți lista de selectare; puteți începe cu sql dinamic nativ, cu cursor ref și apoi înlocuiți-l cu dbms_sql pentru a descrie și extrage coloanele de la cursor.

După cum puteți vedea, Oracle Database 11g conține câteva îmbunătățiri care ajută la scrierea mai eficientă a codului pe PL / SQL.







Articole similare

Trimiteți-le prietenilor: