otrdiena, 2010. gada 19. oktobris

Tabulas ar klusterētu (clustered) indeksu

Rakstā aprakstīts un ar ilustrācijām parādīts, kā dati tiek glabāti un meklēti tabulā, kurai ir klusterēts indekss. Aprakstītas indeksu lapas  īpašības.


Līdzīgi kā rakstā "Tabula bez klusterētā (clustered) indeksa", tiek aprakstīts vienkāršākais gadījums, kad tabula atrodas vienā failā un netiek izmantota datu dalīšana vairākās daļās (partitioning).

Aprakstot klusterētos indeksus, tiks pamainīts veids, kā tiek attēlota lapa:
Šajā gadījumā tiek noņemtas bultiņas no rindas sākuma rādītājiem uz rindām. Joprojām lapai ir (1) galvene, (2) datu rindu sadaļa un (3) rindu nobīdes (row offset) no lapas sākuma sadaļa. Klusterēto indeksu gadījumā šīs bultiņas netiek attēlotas tāpēc, ka turpmāk rakstā tām nebūs būtiskas nozīmes.

Datu glabāšana tabulā, kurai ir klusterēts (clustered) indeks


Attēlā redzams, kā tiek glabāti dati tabulā, kurai ir klusterētais indekss. Kā redzams attēlā, ir vairākas būtiskas atšķirības no tabulas, bez klusterētā indeks. Pirmkārt, tiek izmantota kokveida struktūra, otrkārt, lapas veido divkārši saistītu sarakstu, treškārt, datu lapas (pēdējais līmenis) izskatās līdzīgi kā iepriekš, tomēr pārējajos koka līmeņos tās izskatās būtiski savādāk, ceturtkārt, attēlā nav attēlota IAM lapa ("Datu glabāšana SQL Server"). Bet par visu pēc kārtas.

Kas ir klusterēts (clustered) indekss
Atšķirībā no tabulas bez klusterēta indeksa, tabula ar klusterētu indeksu sakārto datus konkrētā secībā. divas būtiskākās lietas, kas jāzina par tabulu ar klusterēto indeksu- (1) dati ir sakārtoti fiziski pareizā secībā, arī lapas ir savstarpēji saistītas tādā veidā, lai tiktu ievērota sakārtojuma secība. Katrai lapai ir rādītājs uz nākamo un iepriekšējo lapu un (2) ja šādā tabulā ir vairāk kā viena lapa, tad tiek izmantotas īpašas indeksu lapas, ar kuru palīdzību tiek būtiski uzlabota meklēšana šādā tabulā.
Kā redzams iepriekšējā attēlā- datu lapas kopā ar indeksu lapām savā starpā veido kokveida struktūru. Koka saknē vienmēr ir indeksu lapa, savukārt koka beigu virsotnēs- ir datu lapas. 

Indeksu lapas
Indeksu lapa, lai arī rakstā izmantotajos attēlos ir zīmēta mazāka, realitātē ir tieši tāda paša izmēra, kā datu lapa- respektīvi- 8 KB datu. Indeksu lapa attēlota šādi:
Atšķirībā no datu lapām, indeksu lapās glabājas cita veida informācija- atslēgas zemākā vērtība lapā + PID (page ID)- tātad lapa, kurā atrodas dati, kuru mazākā atslēga ir norādīta indeksā. Atslēga ir tās kolonnas vērtība, kura tiek izmantota kā indeksējamā kolonna (piezīme- var veidot klusterēto indeksu arī uz vairākām kolonām vienlaicīgi, bet vienai tabulai nevar būt vairāk kā viens klusterēts indekss).
No tā izriet, ka indeksu lapās ļoti kompaktā veidā var adresēt daudz datu lapu. Precīzi lai izrēķinātu būtu vajadzīgs zināt kolonnas, uz kā ir klusterētais indekss, garumu.
Var secināt, ka jo mazāka ir klusterētā indeksa kolonna(s), jo mazāk indeksa lapu jāizmanto, jo potenciāli īsāks ir meklēšanas ceļš no indeksa sākuma līdz datu rindai.

IAM lapas
Kā minēts rakstā Datu glabāšana SQL Server katrai tabulai un katram indeksam ir vismaz viena IAM lapa. Attēlā lapa nav parādīta, tāpēc, ka indeksa sākuma lapa ir daudz būtiskāka par IAM lapu. Praktiski arī tabulai ar klusterēto indeksu ir IAM lapa, kurā tiek glabāta informācija par indeksam piederošajām lapām un Extents.

Datu rindu mainīšana/pievienošana
Ja vēlamies ievietot jaunu datu rindu, situācija attēlā: 

bet tabulas lapā šai jaunajai rindai nepietiek vietas, tad pēc rindas ievietošanas būs sekojoša situācija:
Tas, kas ir noticis, ir lapu dalīšanās (page split). Identiski notiktu arī gadījumā, ja mēs mainītu rindas datus tā, ka rinda vairāk neietilpst tajā pašā lapā (būtiski atšķirība no Tabula bez klusterētā (clustered) indeksa- ja ir klusterētais indeks, tad nevar rasties pāredresējošie ieraksti). 
Lapu dalīšanās laikā, SQL Server vienu lapu sadala divās, aptuveni vienādās daļās, jaunā lapa tiek pareizi sasieta ar pārējām lapām (rādītāji uz iepriekšējo un nākamo lapu). Jaunais ieraksts atrod savu vietu tajā lapā, kur pēc klusterētā indeksa nosacījumiem tam būtu jāatrodas Piemērs: Lapu dalīšanās (Page splits). Indeksu lapā arī tiek pievienots jauns ieraksts (katrs indeksu lapas ieraksts atbild par vienu lapu). Gadījumā, ja indeksu lapā nepietiek vietas jaunajam ierakstam, arī tajā notiek lapas dalīšanās identiskā veidā. 
Pēc atēla redzams, ka lapu dalīšanās ietver sevī samērā daudz darba. Tātad, no tā arī var izdarīt secinājumu, ka jo mazāk notiek lapu dalīšanās, jo labāk. 

Datu rindu dzēšana
Datu rindu dzēšana pēc būtības ir vienkārša. Vienīgais ko šeit būtu vērts atzīmēt ir tas, ka gadījumā, ja lapā vairāk nav ierakstu, tad lapa tiek "izslēgta" no ķēdes un to var izmantot citām vajadzībām. atšķirībā no tabulām bez klusterētā indeksa, lapu atbrīvošana notiek līdz ar pēdējās rindas dzēšanu no lapas (tabula bez klusterētā indeksa, lapas atbrīvo tikai īpašos gadījumos- to var izlasīt maziem burtiņiem šeit. Lapu ne-atbrīvošana mulsināja veidojot Piemērs: pāredresētie ieraksti (Forwarded records)). 

Datu meklēšana
Datu meklēšana tabulā ar indeksu notiek daudz efektīvāk, kā gadījumā, kad tabulai nav indeksu. Ja tabulai nav indeksu, tad jebkurā gadījumā ir jāpārlasa pilnīgi visa tabula, lai veiktu jebkuru datu atlases/mainīšanas vaicājumu. Ņemot vērā to, ka klusterētais indekss sakārto datus fiziskā secībā, arī veicot intervāla meklējumus (range scan), klusterētais indekss var strādāt ļoti efektīvi.
1. Viena ieraksta atgriešana
Viena ieraksta atrašana nozīmē to, ka jāiziet cauri visu līmeņu indeksu lapām, līdz nonāk pie datu lapas, kurā atrod konkrēto ierakstu. Lai arī konkrētajā piemērā pēc attēla tas neizskatās diezko efektīvi, tas tomēr ir- datu lapu šādā divu līmeņa indeksu lapu gadījumā visdrīzāk ir simtiem datu lapu- atkarībā no klusterētā indeksā izmantotās(ām) kolonnas(u) garuma. līdz ar to trīs lapu pārmeklēšana pret daudziem simtiem ir efektīvāka. 
2. Vairāku secīgu ierakstu atgriešana
Tabulā, kurai ir klusterētais indekss, ir garantēts, ka dati ir sakārtoti secībā pēc indeksa kolonnas(ām). līdz ar to lai atrastu vairākus secīgus ierakstus (tipiski- vaicājumi, kuriem uz attiecīgo kolonnu where daļā ir ">", "<", "Between x And y", arī "Like" speciālgadījumi) pietiek atrast pirmo ierakstu un tad pārējie ieraksti ir blakus. Tā ir ļoti svarīga klusterētā indeksa īpašība). Kad lapā ir pēdējais ieraksts, tiek izmantots tas, ka datu lapas ir savstarpēji saistītas.

Piezīmes par klusterēto indeksu
* Tabulai var būt tikai viens (!tas nozīmē arī tabulas fizisko sakārtojumu) klusterētais indekss, tāpēc derētu padomāt, vai tas tiek izmantots prātīgi.
* 99,9% gadījumu tiek ieteikts visām tabulām veidot klusterēto indeksu. Ir izņēmumi, bet tie ir ļoti, ļoti specifiskos gadījumos noderīgi.
* Indeksa veidošanai būtu jāizvēlas tāda kolonna(s), kuru vērtība(s) ir pēc iespējas dažādas. To lieliski var redzēt pēc attēliem- jo dažādākas ir klusterētā indeksa vērtības, jo precīzāk tiks atrasta datu lapa, kurā ir attiecīgā rinda- līdz ar to noderīgāks ir indekss. (Piemēram, tabula kurā ir 1000 datu lapas, bet indeksā ir tikai 2 unikālas vērtības- tas nozīmē meklējot datu rindu pēc klusterētā indeksa, jebkurā gadījumā sanāks pārmeklēt 1/2 no tabulas)
* Veidojot tabulu un norādot primārās atslēgas kolonnu(as), tai tiek automātiski izveidots klusterētais indekss. Pēc pieredzes- tas lielākoties ir labs variants- primārā atslēga parasti ir unikāla un bieži arī- vienmēr augoša (identity kolonna). Tas palīdz izvairīties no lapu dalīšanās (page splits). Pilnībā lapu dalīšanos tas gan nenovērš, jo ja, piemēram, ir mainīga izmēra kolonnas, tad lapu dalīšanās joprojām var notikt.
* Klusterēto indeksu ir vērts apdomāt likt uz kolonnas, uz kuru tiek bieži veikta secīga meklēšana (range scan). Tomēr atceroties par iepriekšējiem punktiem.
* Tā kā klusterētais indekss nozīmē fizisko sakārtojumu- rūpīgi jāapsver vai to likt uz kolonnu, kurā bieži mainās vērtības. Šādā gadījumā visai iespējams, ka dati bieži būs "jāmētā" pa datu lapām.

Papildus literatūra
* Primārais avots, kas izmantots ir grāmata.
* MSDN rakstā apraksts par tabulu un indeksu organizāciju šeit, par tabulām ar klusterētu indeksu ir šeit (apskatot rakstu versijas, var pārliecināties, ka principi tie paši arī SQL 2008 R2)
* Salīdzinātas tabulas ar klusterēto indeksu un bez tā ir šeit, savukārt no ātrdarbības un labās prakses viedokļa salīdzinošs raksts (tabula bez indeksa vs tabula ar klusterētu indeksu) atrodams šeit.
* Raksts par indeksiem (manuprāt, raksti papildina viens otru) atrodams šeit.

Nav komentāru:

Komentāra publicēšana