piektdiena, 2010. gada 8. oktobris

Tabula bez klusterētā (clustered) indeksa

Rakstā aprakstīts un ar ilustrācijām parādīts, kā dati tiek glabāti tabulā, kurai nav indeksu. Vienlaicīgi dziļāk tiek apskatīts kā dati tiek glabāti lapu ietvaros. Apskatīts, kas notiek datu ievietošanas, dzēšanas, mainīšanas gadījumos tabulā, bez klusetētā indeksa (tādu struktūru sauc par "kaudzi"- heap).


Kā minēts (raksts Datu glabāšana SQL Server), SQL Server tabulu dati tiek glabāti lapās (Pages), kurās tiek glabātas viena vai vairākas datu rindas (atkarībā no rindas garuma). Viena rinda nevar atrasties vairākās lapās, līdz ar to tā nedrīkst būt garāka par 8060 baitiem, ieskaitot papildus informāciju kas tiek glabāta kopā ar rindu. Izņēmums ir tad, ja ir mainīga garuma kolonnas- piemēram, nvarchar, ntext, image. Tādā gadījumā, mainīgā garuma kolonnu dati var tikt glabātas citās, speciāli tam domātās, lapās.

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). Bet sarežģītākie gadījumi ir ar niansēm, tomēr pamata ideja vienmēr paliek tā pati. Līdzīgi kā datu glabāšanas struktūru pamati nav mainījušies jau kopš SQL Server 7.0 laikiem.

Datu glabāšana tabulā, kurā nav klusterēts (clustered) indeks:

Tātad- tiek izmantotas IAM lapas, kurā atzīmē tabulai piederošās lapas (ja tabula mazāka par 8 lapām) vai Extents (ja tabula lielāka par 8 lapām). Viena IAM lapa var rezervēt tabulai pat līdz 512000 atmiņas lapu, tomēr ja ar to ir par maz, tad tiek veidotas papildus IAM lapas.
Tabulas lapas, gadījumā, ja nav klusterēta indeksa, savstarpēji nav saistītas- kā redzams attēlā, IAM lapa ir vienīgais, kas tabulu satur kopā.

Rindas pievienošana, pamatgadījums:
Pamata gadījumā, dati tiek ievietoti secīgi pirmajā brīvajā vietā. Ja nav pietiekami brīvas vietas nevienā no tabulai atvēlētajām lapām vai Extents, tad tabulai tiek iedalīta jauna lapa (vai jauns Extent), kurā secīgi tiek pievienoti jauni dati.

Rindu dzēšana:
Rindas dzēšanas gadījumā īpaši uzmanību jāpievērš tam, ka datu lapā viss paliek tā kā ir bijis, mainās tikai tas, ka konkrētās rindas tiek tikai atzīmētas kā dzēstas. 

Rindas pievienošana, pirmais speciālgadījums:
Ar šo tiek ilustrēta vēl divas svarīga nianses- (1) ievietotā rinda bija tikpat liela, kā tā rinda, kuru iepriekš dzēsām. Tādēļ tās ievietošanai nav nepieciešams pārkārtot lapu. Tāpēc lapa joprojām ir tāda, kāda tā bija sākumā un (2) apakšā tiek atzīmēts, cik tālu rinda atrodas no lapas sākums (row offset)- tas nav sakārtots saraksts, respektīvi- šajā piemērā lapas 4. rinda pēc fiziskā sakārtojuma ir lapas 2. rinda. 

Rindas pievienošana, otrais speciālgadījums:
Tā kā rinda, kuru pievienojām, saturēja vairāk datus nekā parastā rinda, tad lapā nebija pietiekami daudz secīgi brīvas vietas, kurā rindu ievietot (lapas brīvās vietas apjoms ir zināms iepriekš. Ja lapā nebūtu pietiekami daudz vietas rindai, tad tiktu izvēlēta cita lapa, kurā būtu pietiekami daudz vietas). Tādēļ lapa tika pārkārtota, bet jaunā rinda pievienota lapas beigās. Salīdzinoši, šī operācija aizņēma vairāk resursu kā pirmais speciālgadījums.

Rindas datu mainīšana:
Šajā piemērā apskatīts gadījums, kad rinda paliek īsāka (piemēram, rindas nvarchar kolonnā esošās piezīmes "Atļāvu samaksāt vēlāk..." tiek nomainītas uz "Bankrotēja", kā rezultātā rinda palika īsāka par 28 baitiem). Ar ilustrācijām nav aprakstīts gadījums, kad rinda savu garumu nemaina, jo tāds gadījums nav visai interesants. Gadījumā ja rindas garums tiek palielināts un lapā ir pietiekami vietas- notiek līdzīgi kā rindas pievienošanas gadījumā ([1. gadījums]: Piemērs: pāredresētie ieraksti (Forwarded records))

Rindas datu mainīšana, speciālgadījums, kad lapā nepietiek vietas:
Šeit ir lietots saīsinājums RID (no angļu val Row Identifier)- Rindas identifikators sastāv no faila identifikatora (vienkāršos gadījumos datu bāze sastāv tikai no viena datu faila), datu bāzes lapas numura un rindas numura. Tas ir būtiski- jo kā jau ilustrēts iepriekš, rindai mainot savu fizisko atrašanās vietu konkrētā lapā, tās RID nemainās. 
Tātad- lapā nepietika vietas palielinātajai rindai, līdz ar to, tā tika pārnesta uz citu lapu, kurā brīvas vietas pietiek. Rezultātā- oriģinālā rinda palika tur kur bija, bet tajā ir rādītājs uz īsto rindas glabāšanās vietu. Gadījumā ja rindu vēlāk padarītu mazāku un tai pietiktu vietas lapā, kurā tā atradās agrāk- tad rinda tiks pārvietota atpakaļ ([2. gadījums] Piemērs: pāredresētie ieraksti (Forwarded records)). 

Meklēšana
Meklēšana notiek secīgi nolasot visus datus (pieņemot ka tabulai vispār nav indeksu). Kā redzams attēlā, lai atrastu datu rindu ir jāpārmeklē pilnīgi visi tabulas dati (atrodod vajadzīgo datu rindu, nevar zināt vai nav vēl kāda rinda, kas atbilst tiem pašiem meklēšanas kritērijiem). Jāņem vērā arī tas, ka, piemēram, datu rindas mainīšanas gadījumā, no sākuma ir jāatrod rinda ko grasāmies mainīt- respektīvi jāpārmeklē tabula!

Papildus literatūra
* Primārais avots, kas izmantots ir grāmata. Lai arī tā ir par SQL Server 2000, galvenie darbības principi nav mainījušies. Par to var pārliecināties visos citos rakstos. 
* MSDN rakstā apraksts par tabulām bez indeksa (heaps) ir šeit. Lieliski apstiprina iepriekšējā punktā minēto apgalvojumu.
* Reālajā dzīvē tabulas bez indeksa ir ļoti reti kad lietotas un tāpēc atsevišķi raksti par to ir reti sastopami. Tiesa gan, aprakstot indeksus bieži tiek pieminēts kā tas strādā, ja tabula ir bez klusterētā indeksa. (tātad- nākamajā rakstā, kas (plānots) būs par tabulām ar klusterētajiem indeksiem, papildus literatūras atsaucēs visdrīzāk sanāks sastapties gan ar tabulām bez klusterētā indeksa, gan tabulām vispār bez indeksiem)
* [Papildināts 2015-07-22] http://aboutsqlserver.com/2013/12/17/sql-server-storage-engine-heap-tables/ 

Nav komentāru:

Ierakstīt komentāru