170 likes | 244 Views
14. Tiedostojen indeksirakenteet. Tässä luvussa oletetaan, että datatiedosto on jo perustettu jotain rakennetta noudattaen ( järjestämättömänä, järjestämällä fyysisesti tietyn kentän mukaan, käyttämällä hajautustekniikkaa ).
E N D
14. Tiedostojen indeksirakenteet • Tässä luvussa oletetaan, että datatiedosto on jo perustettu jotain rakennetta noudattaen ( järjestämättömänä, järjestämällä fyysisesti tietyn kentän mukaan, käyttämällä hajautustekniikkaa ). • Indeksillä tarkoitetaan saantirakennetta, jonka avulla tietueiden hakemista määrätyn kriteerin mukaisesti saadaan nopeutettua. • Indeksi edustaa ns. toissijaista saantipolkua ( secondary access path ), jonka käyttäminen ei vaikuta tietueiden fyysiseen tallennusrakenteeseen levyllä. • Indeksi voidaan perustaa mille tahansa tietueen tietokentälle, ja se voi olla joko yksin- tai moninkertainen.
14.1. Yksitasoisten indeksien tyypit • Indeksit perustuvat usein järjestetyn tiedoston käyttämiseen, ja indeksien talletusrakenteena käytetään yleisesti B- tai B+-puuta. • Indeksi muistuttaa kirjojen avainsanaluetteloa, jota selaamalla löydetään, millä sivuilla jokin tietty termi kirjassa esiintyy. • Ellei tällaista luetteloa olisi käytettävissä, pitäisi kirjaa lähteä selaamaan alusta loppuun asti tai hyödyntämällä mahdollisesti otsikkojen ja väliotsikkojen nimiä ilmeisimmin oikeiden kappaleiden löytämiseksi ja vastaavasti turhien kappaleiden karsimiseksi. • Indeksi perustuu tyypillisesti tiedostossa olevien tietueiden yhden kentän( =attribuutin ) arvoihin, jotka järjestetään joko nousevaan tai laskevaan suuruusjärjestykseen. • Tärkein saavutettu etu: pystytään käyttämään hyväksi puolitushakua etsittäessä hakuehdon täyttäviä tietueita, kunhan hakuehto perustuu indeksikentän arvoon.
Indeksitiedosto on paljon datatiedostoa pienempi, joten puolitushaku toimii tehokkaasti. • Yksinkertaisia indeksejä on kolmea lajia: • Pääindeksi ( primary index ) perustuu järjestetyn tiedoston järjestysavainkenttään. Siten primääri-indeksikentän arvolla ei tietueissa saa esiintyä duplikaatteja (samaa arvoa kahdesti tai useammin). • Ryvästysindeksi ( clustering index ) sallii indeksikentälle myös duplikaatteja. • Toisioindeksi ( secondary index ) voidaan muodostaa mille tahansa tiedoston kentälle, jonka mukaan tiedosto ei ole valmiiksi järjestetty. • Koska pää- ja ryvästysindeksi perustuvat järjestetyn tiedoston fyysiseen tallennusrakenteeseen, niitä voi tiedostossa esiintyä kerrallaan tarkalleen yksi ja vain jompikumpi indekseistä. Pää- tai ryvästysindeksi on tiedoston pääsaantimenetelmä ( primary access method ). • Sen sijaan toisioindeksejä voi tiedostoa kohti esiintyä kerrallaan useita.
14.1.1. Pääindeksit • Pääindeksi on järjestetty tiedosto, joka sisältää kaksi kenttää ja jonka tietueet ovat kiinteän mittaisia. • Ensimmäiseen kenttään on tallennettuna tiedoston järjestysavaimen arvo, joka on samalla tiedoston pääavain ( primary key ). • Toinen kenttä sisältää puolestaan osoittimen levyblokkiin, josta pääavaimen arvoa vastaava tietue on löydettävissä. • Jokaista levyblokkia kohti on tarkalleen yksi tietue pääindeksitiedostossa. Indeksitiedoston tietue esitetään muodossa < K(i), P(i) >, missä K(i) on i:nnen tietueen pääavaimen arvo ja P(i) kyseisen tietueen levyblokki-osoite. Toisin sanoen, kaikkia datatiedoston tietueita kohti ei ole olemassa tietuetta pääindeksitiedostossa! • Tarkastellaan kirjan kuvassa 13.7. esitettyä esimerkkiä järjestetystä tiedostosta ja pääindeksin soveltamista siihen.
Ensimmäiset kolme pääindeksitiedoston tietuetta näyttäisivät seuraavanlaisilta olettaen, että nimi on tiedostossa pääavaimen asemassa (muussa tapauksessa ei pääindeksiä voitaisi muodostaa, vaan tarvittaisiin ryvästysindeksi!): < K(1) = (Aaron, Ed), P(1) = blokin 1 osoite > < K(2) = (Adams, John), P(2) = blokin 2 osoite > < K(3) = (Alexander, Ed), P(3) = blokin 3 osoite > • Pääindeksitoteutus em. esimerkille on nähtävissä kuvassa 14.1. • Datatiedoston kunkin blokin ensimmäistä ( toisenlaisessa toteutuksessa vastaavasti viimeistä ) tietuetta kutsutaan blokin ankkuriksi. • Indeksin sanotaan olevan toteutukseltaan tiivis ( dense ), mikäli kutakin datatiedoston tietuetta kohti esiintyy tietue myös indeksitiedostossa. Muussa tapauksessa indeksi on harva ( nondense, sparse ). Siten pääindeksi on toteutukseltaan harva. • Pääindeksitiedosto vaatii selkeästi vähemmän muistitilaa kuin datatiedosto, sillä:
Pääindeksitiedostossa on vähemmän tietueita kuin sitä vastaavassa datatiedostossa. • Pääindeksitiedoston tietueet ovat fyysisesti lyhyempiä, sillä ne sisältävät vain kaksi kenttää. ---> Siten indeksitiedoston tietueita mahtuu yhteen blokkiin enemmän kuin vastaavan datatiedoston tietueita, joten haku indeksitiedostosta vaatii keskimäärin vähempien blokkien tutkimista puolitushaulla kuin suora datatiedostosta haku puolitushaulla. Tietue, jonka avainkentän arvo on K, löytyy ( jos se on ylipäätään löytyäkseen tiedostosta ) blokista, jonka osoite on P( i ) siten, että K( i ) K < K( i + 1 ), sillä K on pääavainkentän arvo. • Täten pitää etsiä tietueen oikea sijaintipaikka blokin tarkkuudella indeksitiedostosta, ja sen jälkeen haetaan kyseinen blokki, josta tietue voi löytyä. • Haku pääindeksitiedostoa hyväksi käyttäen on tehokkaampaa kuin suoraan datatiedostosta. Tarkastellaan asiaa seuraavan esimerkin valaisemana:
Esimerkki: Oletetaan, että on opiskelijatiedostossa on 30000 tietuetta. Tietueet ovat kiinteän mittaisia, ja yhden tietueen pituus on 100 tavua. Yhden blokin koko on 1024 tavua. Siten yhteen blokkiin mahtuu 1024/100 eli 10 tietuetta, joten blokkeja tarvitaan yhteensä 30000/10 = 3000 kappaletta. Binäärihaku 3000 blokista maksaa selvästikin maksimissaan log23000 = 12 hakua. Tehdään vertailu, mitä vastaava haku maksaisi käyttämällä pääindeksitiedostoa hyväksi. Oletetaan nyt, että pääavainkentän pituus on 9 tavua ja levyblokkiosoitekentän 6 tavua. Koska pääindeksitiedoston tietueet ovat kiinteän mittaisia, tällöin sen tietueita mahtuu yhteen blokkiin 1024/15 = 68 kappaletta. Jokaista datatiedoston blokkia varten tarvitaan yksi tietue pääindeksiin. Siten blokkeja tarvitaan pääindeksitiedostoa varten yhteensä 3000/68 = 45 kappaletta. Puolitushaku 45 blokista vaatii ajan log245, eli hakuja tarvitaan maksimissaan 6 kappaletta. Lisäksi tarvitaan yksi ylimääräinen haku datatiedoston oikeaan levyblokkiin, joten hakujen yhteismäärä on 7, joka on nopeampi kuin suoraan data- tiedostoon kohdistuneen haun vertailujen määrä 12.
14.1.2. Ryvästysindeksit • Pulmatilanne pääindeksitiedoston käyttämisessä: uuden tietueen lisääminen tiedostoon. • Pitää löytää paitsi oikea sijoituspaikka fyysisessä datatiedostossa, joudutaan lisäksi indeksitiedosto organisoimaan uudelleen, sillä blokkien ankkurit varsin ilmeisesti muuttuvat. • Pulman ratkaisemiseksi voidaan perustaa järjestämätön ylivuototiedosto, kuten todettiin järjestettyjen tiedostojen yhteydessä, tai muodostaa datatiedoston blokkeihin ylivuotoalue linkitetyn listan avulla kuten hajautusten yhteydessä. • Mikäli datatiedoston tietueet on järjestetty fyysisesti muun kuin avainkentän mukaan, käytetään järjestyskentästä nimitystä ryvästyskenttä ( clustering field ). • Tällaista kenttää kohti voidaan ei voida perustaa pääindeksiä, vaan sen sijaan tähän tarkoitukseen kelpaa ryvästysindeksi.
Ryvästysindeksin käyttötarkoitus on kuitenkin sama kuin pääindeksin: tietueiden nopeutunut haku tiedoston fyysisen lajittelukentän arvon mukaisesti. • Ryvästyshakemistossa on tietue jokaista ryvästyskentän arvoa kohti. Jokainen hakemiston tietue sisältää ryvästyskentän arvon sekä osoittimen ensimmäiseen datatiedoston blokkiin, jossa kyseistä tietueen arvoa esiintyy. • Tarkastellaan kirjan esimerkkiä 14.2. • Kannattaa huomioida, että nytkin tietueiden lisääminen datatiedostosta (samoin myös poistaminen) aiheuttavat hankaluuksia, koska datatiedosto on fyysisesti järjestetty. Tällöin muutos datatiedostossa voi aiheuttaa muutoksia myös ryvästysindeksitiedostossa. • Usein datatiedosto toteutetaan siten, ettei saman blokin sisällä esiinny tietueissa kuin yhtä ryvästyskentän arvoa, mikä poistaa ryvästystiedoston osoittimien uudelleenjärjestelyn tarpeen. Tällöinkin kuitenkin täysin uuden ryvästyskentän arvon luonti aiheuttaa vaikeuksia. • Kuten pääindeksikin, myös ryvästysindeksi on toteutukseltaan harva, sillä kukin ryvästyskentän arvo on edustettuna hakemistossa ( =ryvästysindeksitiedostossa ) vain kertaalleen.
6.1.3. Toisioindeksit • Ryvästysindeksi muistuttaa toteutuksensa puolesta laajennettavaa hajautusta ( kts. kurssin ulkopuolinen kirjan kappale 13.8.3 ). • Myös toisioindeksi on järjestetty tiedosto, jonka tietueilla on kaksi kenttää. • Ensimmäinen kenttä edustaa datatiedoston jonkin sellaisen kentän arvoa, jonka mukaan datatiedosto ei ole fyysisesti järjestetty. • Toinen kenttä on puolestaan joko blokki- tai tietueosoitin datatiedostoon. • Yhtä datatiedostoa kohti voi olla perustettuina useita toisioindeksejä. • Toisioindeksin toteuttamiseen vaikuttaa, onko indeksoinnin kohteena datatiedoston vaihtoehtoinen avainkenttä (ei kuitenkaan fyysisen tallennuksen mukainen järjestysavain) vai kenttä, jonka arvoilla esiintyy duplikaatteja. • Tarkastellaan aluksi vaihtoehtoisavaimeen perustuvaa toisioindeksiä ( kirjan esimerkki 14.4 ).
Koska datatiedosto ei ole fyysisesti järjestetty vaihtoehtoisavaimen suhteen, ei voida käyttää hyväksi blokkiankkureita. Täten jokaista datatiedoston tietuetta kohti on oltava tietue myös toisioindeksitiedostossa --->toisioindeksi on tiivis. Siten toisioindeksitiedostosta haku kestää jossain määrin kauemmin kuin pääindeksistä. • Toisioindeksin perustamisesta saatava hyöty on kuitenkin huomattavasti suurempi kuin pääindeksin perustamisesta, kun vertailukohtana on pelkän fyysisesti järjestetyn tiedoston käyttäminen ilman indeksointia, sillä pääindeksi voitaisiin kuitenkin korvata suoraan datatiedostoon kohdistuvalla puolitushaulla, kun taas toisioindeksille vaihtoehtona olisi lineaarihaku! • Esimerkki: Oletetaan, että aikaisemmin pääindeksin yhteydessä tarkasteltuun 30000 tietueen opiskelijatiedostoon perustetaan toisioindeksi jonkin muun avainkentän kuin tiedoston fyysisen järjestysavainkentän suhteen.Yhden levyblokin koko on 1024 tavua. Oletetaan nyt, että vaihtoehtoisenkin avainkentän pituus on 9 tavua ja levyblokkiosoitekentän 6 tavua. Koska myös toisioindeksitiedoston tietueet ovat kiinteän mittaisia, tällöin sen tietueita mahtuu yhteen blokkiin 1024/15 = 68 kappaletta, kuten oli tilanne pääindeksinkin kohdalla.
Jokaista datatiedoston tietuetta varten tarvitaan yksi tietue toisioindeksiin. Siten blokkeja tarvitaan toisioindeksitiedostoa varten yhteensä 30000/68 = 442 kappaletta. Puolitushaku 442 blokista vaatii ajan log2442, eli hakuja tarvitaan maksimissaan 9 kappaletta. Lisäksi tarvitaan yksi ylimääräinen haku datatiedoston oikeaan levyblokkiin, joten hakujen yhteismäärä on 10, joka on absoluuttisesti vain hieman enemmän kuin haku samasta datatiedostosta pääindeksin avulla, mutta ero lineaarihaun keskiarvoon ( 1500 blokkia ) on valtava. • Toisioindeksi voidaan rakentaa myös sellaiselle datatiedoston kentälle, joka ei kelpaa avaimeksi ( arvoilla esiintyy duplikaatteja ). • Vaihtoehtoisia toteutustapoja: 1. Toistetaan toisiohakemistossa indeksoinnin kohteena olevan kentän keskenään samoja arvoja yhtä monta kertaa, kuin niitä esiintyy datatiedostossa. Tällöin toisioindeksistä tulee tiivis. Esimerkki: Henkilön nimen mukaan fyysisesti järjestetty työntekijä- tiedosto haluttaisiin indeksoida myös osastonumeron mukaan. Tällöin pitäisi kutakin osastonumeroa toistaa niin monta kertaa kuin osastolla on työntekijöitä.
Esitellään toisioindeksi vaihtelevan mittaisina tietueina, jossa jokaista indeksikentän arvoa seuraa osoitinlista niihin datatiedoston blokkeihin, joissa kyseistä kentän arvoa esiintyy. Koska kutakin indeksikentän arvoa edustaa indeksissä vain yksi tietue, toisioindeksistä tulee tällä toteutuksella harva. • Pidetään toisioindeksitiedoston tietueet kiinteän mittaisina, ja asetetaan kutakin indeksikentän arvoa kohti osoitin erilliseen blokkiin, joka sisältää osoittimet kaikkiin niihin datatiedoston tietueisiin, joissa tiettyä indeksikentän arvoa esiintyy. Mikäli johonkin indeksikentän arvoon liittyvät kaikki tietueosoittimet eivät mahdu niille varattuun blokkiin, joudutaan turvautumaan ylivuotoalueiden käyttöön. Myös tämä vaihtoehto johtaa harvaan indeksiin. Tarkastellaan kirjan esimerkkiä 14.5. • Vaihtoehdot 1 ja 2 aiheuttavat muutoksia puolitushakualgoritmiin, sillä vaihtoehdossa 1 esiintyy hakukentässä duplikaatteja ja vaihtoehdossa 2 tietueet eivät ole kiinteän mittaisia. • Vaihtoehdossa 3 tarvitaan yksi ylimääräinen blokkihaku osoitinblokkirakenteen tähden, mutta tietueiden haku ja lisäys ovat suoraviivaisempia kuin vaihtoehdoissa 1 ja 2. Siten vaihtoehto 3 on yleisimmin käytössä oleva. • Toisioindeksi voidaan tulkita datatiedoston ns. loogiseksi lajitteluksi indeksikentän mukaan.
14.2. Monitasoiset indeksit • Monitasoisen indeksin tavoitteena on pienentää hakuaikaa log2bi:stä, missä bi on indeksitiedoston blokkien lukumäärä, siten, että logaritmin kantaluku kasvaa. • Hakemistotasot numeroidaan ykkösestä alkaen siten, että tasolla 1 on osoitteet datatiedoston blokkeihin, tasolla 2 tason 1 blokkeihin jne. Korkeimmalla hakemistotasolla t on ainoastaan yksi blokki, joka sisältää osoitteet tasolle t-1. • Merkintä bfri, joka tarkoittaa yhteen blokkiin mahtuvien indeksitiedoston tietueiden lukumäärää, tarkoittaa samalla hakemiston laajenemista tasoa kohti. Tarkasteltaessa monitasoisia indeksejä bfri:tä vastaa merkintä fo( = fan-out ). • Oletetaan, että datatiedoston sisältämät r tietuetta on tallennettu b blokkiin levyblokin koon ollessa B. Muodostetaan tiedostolle aluksi yksinkertainen pääindeksi siten, että indeksitiedoston tietueen pituudeksi tulee Ri. Tällöin yhteen blokkiin mahtuu fo ( = bfri) = B / Ri indeksitiedoston tietuetta. Jokaista datatiedoston blokkia kohti tarvitaan yksi tietue pääindeksiin. Siten ensimmäisellä indeksitasolla tarvitaan blokkeja b1 = b / fo kappaletta.
Haku indeksitiedostosta vaatisi nyt ajan log2b1, mutta jos b1 > fo, s.o. indeksitiedosto ei mahdu kokonaisuudessaan yhteen blokkiin, voidaan hakua tehostaa rakentamalla uusi hakemistotaso 2, jonka tietuepituus on sama kuin tasolla 1 eli Ri. Koska 1. hakemistotaso on järjestetty tiedosto kuten datatiedostokin, voidaan siinäkin käyttää hyväksi blokkiankkureita. Täten riittää, että hakemistotasolta 2 on olemassa linkit kaikkiin tason 1 käyttämiin blokkeihin. • Tasolla 2 tarvitaan nyt selvästikin b2 = b1 / fo tietuetta. Täten hakemistotason 2 tietueiden määrä on b2 = b1 / fo = ( b / fo ) / fo kappaletta. • Esimerkki: Jos datatiedostossa on 3000 blokkia, blokkikoko on 1024 ja indeksitiedoston tietuepituus on 15, mahtuu yhteen blokkiin 1024/15 = 68 pääindeksitiedoston tietuetta. Tällöin yksinkertaisen pääindeksin rakentaminen vaatisi tilaa 3000/68 = 45 blokkia. Jos haluttaisiin perustaa toinen hakemistotaso, siellä tarvittaisiin yksi tietue kutakin 1. hakemistotason blokkia varten. Koska myös 2. hakemistotason tietuepituus on 15, mahtuisivat kaikki sen tietueet yhteen blokkiin, sillä ( 3000/68 ) / 68 = 45/68 = 1.
Hakemistotasojen maksimimäärää merkitään t:llä. Uusia hakemistotasoja voidaan perustaa niin kauan, kunnes koko viimeksi perustettu hakemistotaso mahtuu yhteen blokkiin. Hakemiston tasojen maksimimäärä t saadaan laskettua kaavasta t = ( logfor1 ), missä r1 edustaa hakemiston tasolla 1 olevien tietueiden lukumäärää. • Monitasoinen hakemisto voidaan perustaa samalla periaatteella myös ryvästys- tai toisioindeksille, kunhan jokainen indeksitietue on kiinteän mittainen, eikä indeksikenttä sisällä duplikaatteja. • Esimerkki: 30000 opiskelijan tiedostolle voitaisiin rakentaa vaihtoehtoisen avainkentän mukaan 3-tasoinen toisioindeksi, sillä t = ( log6830000 ) = 3. • Moninkertainen indeksointi tarjoaa hyvin nopean haun, sillä blokkihakuja tarvitaan ainoastaan t + 1 kappaletta! • Jos ( monitasoinen ) pääindeksi on harva, joudutaan epäonnistuneen haun yhteydessä tutkimaan datatiedoston blokki, jossa haettava tietue olisi voinut sijaita. Tiivistä indeksiä käytettäessä olisi haun epäonnistuminen ollut todettavissa jo alimman tason ( tason 1) indeksitiedostossa.
Tarkastellaan kirjan esimerkkiä 14.6 ( esimerkki 2-tasoisesta pääindeksistä ). • Tarkastellaan kirjan algoritmia 14.1, joka suorittaa hakua t-tasoisesta pääindeksistä. • IBM:n ISAM-systeemissä ( Indexed Sequential Access Method ) on käytössä levyn rakennetta myötäilevä 2-tasoinen sylinteri-indeksointi, jossa hakemisto perustuu ensisijaisesti sylinterin numeroon levypakassa ja tämän jälkeen uraan yksittäisen sylinterin sisällä. • Myös monitasoisessa indeksoinnissa tietueiden lisääminen, päivittäminen ja tuhoaminen aiheuttavat vaikeuksia, sillä kaikki indeksitiedostot ovat fyysisesti järjestettyjä tiedostoja. • Yksi ratkaisuvaihtoehto: dynaaminen monitasoinen indeksi, jossa jätetään blokkeihin jonkin verran tyhjää tilaa uusien tietueiden tallentamiseksi. Tämä toteutetaan usein käyttämällä tietorakenteena B- tai B+-puita.