Efektīva (vairāk vai mazāk) SQL un PL/SQL vadlīnijas

oktobris 15, 2007

1. Iespēja kaut ko izdarīt visātrāk ir to nedarīt vispār, tāpēc par katru SQL teikumu būtu jāpārliecinās:

  • vai tas vispār ir vajadzīgs, varbūt to var nemaz nepildīt,
  • vai to tiešām ir nepieciešams pildīt tik daudz reižu (ciklā), varbūt to var pildīt tikai vienreiz (piemēram iegūt kodu no db, aizpildīt mainīgo ar sistēmas datumu utml),
  • varbūt to var pildīt tikai kādos speciālos gadījumos (if, case).

2. Pēc iespējas jādomā kopas operācijās. Jāmēģina izvairīties no procedurālas SQL teikumu sasaistes. Ja problēmu ir iespējams atrisināt tikai ar SQL līdzekļiem, tad vispārējā gadījumā tā arī jādara. Jo sevišķi jāmēģina izvairīties no SQL konstrukcijām, kas ir ievietotas PL/SQL ciklos.

3. Dinamisko SQLu ir atļauts lietot tad un tikai tad, ja ar statisko SQLu uzdevumu nav iespējams izpildīt.

4. Ja tomēr nepieciešams izmantot dinamisko SQLu un jo sevišķi, ja ir paredzams, ka tas notiks bieži, tad ir jāizmanto EXECUTE IMMEDIATE kopā ar USING klauzu, lai tiktu lietoti bind variables.

5. Dinamiski ģenerējot SELECT teikumus ar iepriekš nezināmu skaitu parametru (tipiski izvērstām meklēšanas iespējām) ir jāizmanto konteksta iespējas (CREATE OR REPLACE CONTEXT), lai sistēma netiktu pārpludināta ar tikai vienreizlietojamiem unikāliem SQL teikumiem, kas nelieto BIND VARIABLES.

6. Ir jāmēģina izvairīties no lietotāja definētu funkciju izsaukšanas SQLā, jo sevišķi, ja attiecīgais SQLs tiek izpildīts bieži vai arī lietotāja definētā funkcija tiek izsaukta daudz reižu viena SQL teikuma ietvaros, jo tiek apstradāts liels datu apjoms. Tā vietā lietotāja definētā funkcija jāmēģina iekļaut pamata SQL teikumā.

7. Ja PL/SQL kodā no datubāzes jāiegūst mainīgie, kas pēc tam nemainās un tiek vairākkārt izmantoti, tad tos vēlams inicializēt vai nu pakotnes ķermenī (bet tikai tad, ja vērtība datubāzē NEVAR mainīties starp vairākiem pakotnes izsaukumiem) vai arī procedūras sākumā (ja vērtība datubāzē var mainīties starp vairākiem pakotnes izsaukumiem).

8. UPDATE operācijām pēc iespējas jāveic koriģēšana tikai tām kolonām, kas patiesi ir mainījušās.

9. Visiem SELECT, UPDATE, INSERT INTO..SELECT FROM, MERGE un DELETE, kas nav triviāli (nenotiek uz vienu tabulu pēc primārās atslēgas) vajadzētu noskaidrot potenciālo izpildes plānu lietojot tādus rīkus kā EXPLAIN PLAN vai AUTOTRACE SQL*Plusā vai izmantojot atbilstošu funkcionalitāti PL/SQL Developer vai SQL Navigator vai līdzīgos vizuālajos rīkos.

Vērtējot izpildes plānu jāņem vērā šādi faktori:

  • Ja darbība tiks izpildīta ļoti bieži un atgriezīs mazu rezultātu kopumu, tad iesaistītajām operācijām būtu jānotiek pēc indeksa(-iem) un ir jāizvairās no tabulu full scan.
  • Ja darbības rezultātam ir nepieciešams pārskanēt visu tabulu, tad ir jāveic full scan pa visu tabulu un jāizvairās no tabulu kombionēšanas (join) izmantojot nested loops uz šo tabulu.
  • Izpildes plānam darbu būtu jāsāk no tabulas, kura ir visselektīvākā, t.i., kur attiecība <Paredzamais atgriezto ierakstu skaits>/<Viss tabulas ierakstu skaits> ir vismazākais, lai kopsummā veicot pieprasījumu tiktu parbaudīta iespējami mazākā ierakstu kombinācija datubāzē.

10. Hintu (ne)lietošana. Izpildes plāni pēc iespējas optimāli būtu jāpanāk nelietojot hintus, bet izmantojot datu bāzes statistikas. Tāpēc arī par izpildes plāna pareizību var ar zināmu drošību pārliecināties tikai līdzīga satura un apjoma (testa, produkcijas) datu bāzē, kurai ir veikta atbilstoša statistiku rēķināšana un ir līdzīga konfigurācija.

10.1. Ja tas nav iespējams, tad pēc iespējas jālieto hinti, kas dod optimizatoram (optimizer) papildus informāciju, bet tieši nenosaka plāna izpildes veidu:

  • ALL_ROWS – mērķis ir iegūt visu rezultātu ar iespējami mazāko resursu patēriņu;
  • FIRST_ROWS (n) – mērķis ir iegūt pirmās (n) rindiņas pēc iespējas ātrāk;
  • DYNAMIC_SAMPLING (n) – dinamiski rēķina statistikas, atkarībā no dotā līmeņa n. Informācija par līmeņiem. Vērtīgs, ja statistikas netiek rēķinātas, kā arī priekš pagaidu tabulām (temporal tables).
  • DRIVING_SITE (table) – ja vaicājuma izpilde notiek vairākās datubāzēs izmantojot datubāzes linku, tad norāda kurā datubāzē vaicājums tiks izpildīts.
  • CARDINALITY (n) – norāda sagaidāmo ierakstu apjomu vaicājumam. Sevišķi noderīgs, ja nepieciešams izmantot tipus.

10.2. Hinti, kurus ieteicams izmantot tikai tad, ja ir 100% pārliecība par savu taisnību un kā pēdējo līdzekli:

  • FULL (table) – ja ir pilnīga pārliecība, ka ir nepieciešama visas tabulas pārskanēšana, lai iegūtu rezultātu, tipiski varētu noderēt atskaitēm, pilnīgi nepieņemams tipiskai datu ievadei/attēlošanai.
  • LEADING (table) – ja ir pilnīga pārliecība, ka vaicājuma izpilde jāsāk ar konkrētu tabulu un statistiku rēķinašana tabulām un indeksiem nedod vēlamo rezultātu.
  • Speciālos gadījumos, ja ir jāveic liela datu pievienošana kādā tabulā, tad var izmantot APPEND – paturot prātā, ka šīs operācijas rezultātā izveidotos datus nav iespējams atjaunot bez pilnas rezerves kopijas, kā arī, ka pēc šis operācijas ir jābeidz transakcija (COMMIT, ROLLBACK), ja vēlas veikt kādas darbības ar izmainīto tabulu.

10.3. Jebkuru citu hintu vajadzētu lietot tad un tikai tad, ja tā lietotājs pilnībā apzinās šī hinta sekas, piemēram, INDEX, INDEX_ASC vai INDEX_FFS – ir pilnīga pārliecība, ka indekss vienmēr būs tāds pats kā sākumā (saturēs tās pašas kolonas), indekss netiks nomests (drop), indekss netiks pārsaukts, šis indekss jebkuros apstākļos būs patiesi īstais un vienīgais, kas derēs vislabāk, lai iegūtu nepieciešamo rezultātu.

10.4. RULE hintu vajadzētu lietot tad un tikai tad, ja cilvēks zin, saprot un spēj izskaidrot visus RBO likumus, kas to nosaka (http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96533/rbo.htm#38864 un http://www.oreilly.de/catalog/orsqltunpr/chapter/).

Turpmākā lasāmviela: