# Teema: Andmebaasi kavandamine ## Küsimus: Kas andmebaasi disainiprobleemid mõjutavad andmebaasirakenduste loomist ja nende rakenduste toimimist? **Vastus:** Jah, mõjutavad küll. Ja kuidas veel. Mulle meenub reklaam, kuidas hästi korrastatud laost on võimalik kaupa kergesti üles leida, samas kui korratust laost on kauba ülesleidmine keeruline ja ettevõtte töö on tänu sellele raskendatud. Sama kehtib ka andmebaasi andmestruktuuride kohta. Hästi ja läbimõeldult ülesehitatud ning vigadeta realiseeritud andmestruktuuride põhjal on lihtsam andmeid otsida, andmeid muuta ning andmebaasirakendusi arendada kui andmebaasi põhjal, kus sellega on probleeme.14.06.2022 ilmus uudis selle kohta, kuidas Eesti vallad ja linnad on uue E-ehitisregistri vigade tõttu ehitus- ja kasutuslubade menetlemise tähtaegadega hätta jäänud. Seadus näeb ette menetlemiseks lühikesed tähtajad. Uue süsteemi vead on nii suured, et omavalitsused ei suuda tähtajaks menetlusprotsessi lõpuni viia. Ehitisregistris on probleeme ametnikule suvaandmete kuvamises, dokumentide meelevaldses sidumises registri enda poolt ja menetlusdokumentide kustumises. Probleemid olid nii suured, et mitmed omavalitsused ja teised ehitusloa menetlusega seotud asutused on teavitanud, et nad on ehitusloa taotluste menetlused peatanud seni, kuni ehitisregister korda saab. Harjumaa Omavalitsuste Liit tegi ettepaneku probleemide lahendamiseni kasutada vana registri versiooni. Majandus- ja kommunikatsiooniministeeriumi (MKM)  hinnangul pole see mõistlik, sest probleemid on lahenemas ja vanas süsteemis on vanade tehnoloogiate kasutamise tõttu turvaaugud, mille paikamine ajutiseks kasutamiseks oleks ebamõistlikult kallis. MKM pressiesindaja sõnul ei tulenenud registri uue versiooni peamised probleemid üldse tarkvaravigadest, "vaid eelmise ehitisregistri versiooni kaardistamata andmebaasivigadest, mis testimise käigus kahjuks ei ilmnenud."2022. aasta suve lõpuks olid probleemid alles ja suve jooksul rääkisid mitmed kinnisvaraarendajad, kuidas viivitused nendele tõsiseid kahjusid tekitavad. Eesti omanike keskliidu esimees Priidu Pärna avaldas repliigi, kus oli väga kriitiline riigi IT-süsteemide arendamise juhtimise osas. Ennast e-riigiks nimetav riik ei saa endale lubada uue süsteemi kasutuselevõttu nii, et see tekitab kaose. Eelmine e-ehitusregister oli väga halva kasutatavusega. Näiteks puukuuri ehitisteatise esitamine võttis Priidu Pärnalt kolm päeva. Paraku uus süsteemi versioon sellele pandud ootuseid ei õigustanud, sest uus on veel hullem. Priidu Pärna kirjutab: "Õigusriigi põhimõttega on absoluutses vastuolus ja põhiseaduse vastane, kui seaduse mittetäitmist (lubade väljastamise tähtaegade mittejärgimist) põhjendatakse kuid infosüsteemi mittetoimimisega." Oleme olukorras, kus IT-süsteem ei toeta "äri" toimimist, vaid "äri" peab ennast kohandama vastavalt IT-süsteemi puudustele. Priidu Pärna juhib tähelepanu riigivastutuse seadusele, mille kohaselt peab riik hüvitama enda tegematusest tekkinud varalise kahju. Kokkuvõttes maksab arve maksumaksja.Loo moraal - IT-süsteemi arendajate vastutus pole väiksem kui arstil. Halvasti tehtud IT-süsteem võib tähendada lennuki taevast alla kukkumist, õhkulennanud tuumajaama, või (äriinfosüsteemide näitel) tohutut hulka kasutajate raisatud aega/närvirakke koos sellest tuleneva suure majandusliku kahjuga, mille lõpuks maksavad kinni maksumaksjad või teenuse tarbijad. ## Küsimus: Kas andmete andmebaasi tasemel valideerimine (eelnevalt defineeritud reeglitele vastavuse kontrollimine) on hea mõte või mitte? **Vastus:** Minu arvates on hea mõte. Järgnev tekst üritab seda põhjendada.Väide: Kui rakenduse tasemel andmeid valideeritakse, siis andmebaasi tasemel pole seda enam vaja teha, sest see on liiga keeruline. Vastus: Kõik sõltub sellest, kui oluliseks andmete korrektsust peetakse. Muidugi ei taga kontrollid, et andmed on alati sisuliselt õiged, kuid need aitavad vähendada andmebaasi sattuvate ebaõigete andmete hulka. Kui kontroll realiseerida n rakenduses (mida on pidevalt vaja edasiarendada), mis on tehtud m firma poolt (igaühel oma CASE vahendid, dokumenteerimise standardid ja tavad - probleem: kuidas neile kitsenduste olemasolu kõige paremini kommunikeerida) kasutades y erinevat keelt ja kus on z vormi mille kaudu saab andmeid muuta ning kõigele lisaks on veel g skripti, mis laadivad andmebaasi regulaarselt uusi andmeid, siis kontrolli veelkordne teostamine andmebaasi tasemel ei tundugi enam nii suur täiendav pingutus - pealegi kui sellest tõuseb olulist täiendavat kasu. Teemast hetkeks kõrvale kaldudes - deklaratiivsete reeglite jõustamine pole suurem pingutus kui Java koodi kirjutamine. See võib olla pingutus indiviididele, kes kahe tabeli ühendamise päringu kirjutamiseks peavad pool tundi googeldama. Siinkohal on abiks oma tööjõu parem valimine ja koolitamine. Elav klassik hr Leo Võhandu on öelnud, et umbes 1/3-le inimestest on võimatu deklaratiivset, hulkade töötlemisel põhinevat keelt korralikult selgeks õpetada - nad ei saa sellest aru ja ei hakkagi kunagi korralikult aru saama. Õpetamise praktikuna võin seda väidet kinnitada. Andmebaasi taseme kontrollidest pole võimalik meelega mööda hiilida või kogemata "mööda tuigerdada". Ma ei ole kindlasti andmete rakenduse tasemel valideerimise vastu, sest see võimaldab anda kasutajale kiiremat ja selgemat tagasisidet ning vähendada võrguliiklust, sest leitud ebakorrektseid andmeid ei hakata üle võrgu saatma. Kuid kaitse (kui kaitstavat objekti tahetakse tõesti kogu hingest kaitsta) peaks olema mitmekihiline - kui üks kiht veab alt, siis on veel vähemalt üks kiht, mis löögi vastu võtab ja tagasi põrgatab. Autol panete uksed lukku, panete eraldi rooliluku panete kõigele lisaks veel signalisatsiooni peale. Mõni jätab isegi kurja koera autosse. Keegi ei tule selle pealegi, et seda oleks "liiga palju". Kui rakenduses x jäi vormile y kontroll peale panemata, siis testimisel tekib veateade ja kohe on selge, et vormi juures on jäänud midagi tegemata. Möönan, et kitsenduste täidetuse kontrolli realiseerimine lisaks andmebaasile ka rakendustes tähendab lisatööd ja dubleerimist. Kontrolliloogika dubleerimisega tekivad samad probleemid kui andmete liiasusega - muudatusi tuleb teha mitmes kohas (st tööd on rohkem) ning kui muudatusi ei tehta kõigis vajalikes kohtades, siis tulemuseks on süsteemi erinevate osade vastuoluline käitumine. Lisaks andmete valideerimisele on veel põhjuseid, miks andmebaasi tasemel deklareeritud kitsendused osutuvad kasulikuks. Möönan, et järgnevate võimaluste kasutuselevõtu osas on tänapäeva tarkvarasüsteemidel veel palju ära teha. Andmekäitluskeele lausete (päringud ja andmemuudatused) optimeerimine ja automaatne lihtsustamine. Eesmärgiks on saavutada lausete kiirem täitmine. Kitsendused annavad andmebaasisüsteemile infot andmebaasis olevate andmete tähenduse kohta ja selle info alusel saaks andmebaasisüsteem asendada nii mõnegi käivitatava lause oluliselt lihtsama kuid semantiliselt samaväärse lausega. Sellise semantilise teisendamise esimeseks pääsukeseks on tabelite elimineerimise teisendus, mida muuhulgas toetavad PostgreSQL ja Oracle. Arendussüsteemides, mille puhul genereeritakse rakendus andmebaasi põhjal (nagu näiteks Oracle APEX), saaks põhimõtteliselt teha nii, et andmebaasi tasemel jõustatud ja süsteemikataloogis talletatud kitsenduste põhjal luuakse automaatselt rakenduse kood, mis samuti kitsenduse täidetust kontrollib. Näiteks APEX puhul võiks automaatselt tekkida tabeli alusel loodud lehega seotud Valideerimised (validations). Omaette keerukus tõuseb muidugi sellest, kuidas taolises olukorras kitsenduste muudatusi sünkroniseerida. Kitsendused aitavad andmebaasisüsteemil mõista andmete tähendust ja aitavad seda teha ka arendajatel. Sisuliselt dokumenteerivad need andmetele esitatavaid nõudeid - see on eriti kasulik olukorras kus dokumentatsiooni peaaegu ei ole või on sellel lastud vananeda. Samuti annavad kitsendused olulist infot, mille alusel otsida andmebaasi skeemist automaatselt mitmesuguseid disainivigu (näiteks erinevate SQL-andmebaasi disaini antimustrite esinemisi). Vigu saab otsida päringutega andmebaasi süsteemikataloogi põhjal. Kui rakenduse lähtekood on suletud ja sellesse ei ole võimalik muudatusi teha või kui tegemist on pärandkoodiga, mida keegi ei oska/taha muuta, siis on andmebaasi tasemel jõustatud kitsendused viis, kuidas täiendavaid andmete kontrolle ikkagi süsteemi sisse viia. Eesti infoturbestandard toob ühe andmebaasisüsteemidega seotud ohuna välja välisvõtme kitsenduste mittejõustamise andmebaasis, sest tänu sellele võib tekkida andmete terviklikkuse kadu: "Kui tabelite viitetervikluse nõuet pole andmebaasi projekteerimisel järgitud, võivad andmebaasi sattuda väärad andmed. Kui tegu on kriitiliste andmetega (nt raamatupidamisandmed või tööstussüsteemi juhtandmed), siis võib aja jooksul tekkida sellest ulatuslik kahju." (E-ITS rakendusjuhend, 2022)Väide: Andmebaasis kontrollide realiseerimine on liiga keeruline. Vastus: Tõsi - kui kasutada trigereid keerukamate reeglite kontrollimiseks, siis on nendesse lihtne teha vigu nii, et teatud olukorras laseb kontroll läbi ebakorrektseid andmeid. Samu vigu saab muide teha ka rakenduses. Deklaratiivsete kitsenduste puhul selliseid probleeme ei teki, sest ütlete süsteemile mida on vaja kaitsta ning süsteem ise valib parima algoritmi kuidas kontrolli läbi viia. See, et tänapäeva SQL-andmebaasisüsteemid ei võimalda luua üldiseid deklaratiivseid kitsendusi (CREATE ASSERTION) on minu hinnangul üks tänapäeva SQL-andmebaasisüsteemide suuremaid puuduseid. Abi on generaatorsüsteemidest nagu RuleGen. Väide: Andmete valideerimine andmebaasi tasemel on halb, sest muudatuste sisseviimiseks peab andmebaasi töö peatama. Vastus: Võimalused nagu näiteks Online Table Redefinition ja Edition-Based Redefinition aitavad seda probleemi leevendada. Tänapäeva andmebaasisüsteemid võimaldavad kitsendusi kiiresti sisse ja välja lülitada ning sama saab teha trigeritega. Olen nõus, et paljugi on veel vaja ära teha. Samas mõelge ka sellele, et kitsendus, mille jõustate andmebaasis, jõustub kohe loomise järel ja rakendub kõigile andmemuudatustele sõltumata sellest, millisest allikast (rakendusest, skriptist, administreerimise programmist) need pärinevad. Kas see kui jõustatava reegli muutumise tõttu tuleb korraga asendada kõik rakendused uue versiooniga on kuidagi olemuslikult lihtsam ja parem? Kas see kui erinevates sama baasi kasutavates rakendustes on realiseeritud erinevad versioonid andmete kontrolli reeglitest (üks rakendus leiab, et isikukood peab olema Eesti isikukood; teist rakendust on juba uuendatud ja see lubab Eesti ning Läti isikukoode) on olemuslikult hea? Toodi näide selle kohta, et on vaja hakata registreerima ka Läti ja Leedu isikukoodiga isikuid. Kena! Andmebaasist kitsenduse kustutamine või kitsenduse väljalülitamine võtab vaid hetke. Kas tõesti leiate, et sama asja tegemine m rakenduse z vormis ja lisaks veel g skriptis võtab sama vähe aega?! Ma võin andmebaasis muuta tabelite struktuuri ja see, et mõne kitsenduse rakenduse tasemel kontroll seetõttu enam ei toimi tuleb välja alles testimisel. Samas andmebaasis on andmebaasiobjektide vahelised seosed andmebaasisüsteemi jälgimise all, info nende kohta on süsteemikataloogis ja a) süsteem ei lase mul teha struktuurimuudatusi, mis viivad mõne teise objekti ebakorrektsesse seisu või b) ma saan nende seoste kohta vähemalt süsteemikataloogist päringutega infot otsida. Väide: Andmete valideerimine andmebaasi tasemel mõjub halvasti jõudlusele. Vastus: Suure hulga andmete tabelisse laadimisel on sõltuvalt süsteemist võimalik kitsendusi ajutiselt välja lülitada ning laadimise lõppedes uuesti sisse lülitada. Kui Teil on ühe tabeli mitut rida või mitme tabeli ridu hõlmavad kontrollid (näiteks välisvõtme kitsenduse kontroll), siis selle rakenduse tasemel realiseerimine tähendab ikkagi päringuid baasi vastu, vajadusel andmeelementide lukustamist. Mille alusel arvatakse, et selline lahendus on kuidagi jõudluse poolest parem?! Andmebaaside lisamaterjalide kodulehel on lõputöö Ärireeglite realiseerimine PHP ja PostgreSQLi abil. Tsiteerin selle töö lõppjäreldusi: "Nende uuringute tulemuste põhjal jõuti järeldusele, et enamuse ärireegli tüüpide realiseerimise puhul on PostgreSQLi kasutamine realisatsiooniks mõistlikum, mis tähendab, et kood on seal lihtsam, kompaktsem ja muudatuste sisseviimisel mugavam. Ka süsteemi töökiirus ärireegli kontrolli läbiviimisel ja realiseerimisel oli suurem. Vigade parandus oli PostgreSQLi puhul tihtipeale kergem, kuid mõningatel juhtudel ei olnud mõlemad süsteemid võimelised arusaadavalt vea põhjust kuvama. Muudatuste sisseviimine on andmebaasi tasandil kergem selles osas, et siis ei pea muutmist vajavat kohta kaua otsima ning pole vaja ka rakendust toimingusse kaasata: kõik muudatused saab andmebaasis ära teha. Lisaks pakub andmebaas palju võimalusi ärireeglite realiseerimiseks, mida PHPs teha ei saa: vaated, domeenid, klassist klassi pärimine (disjoint), trigerid ja muud. Ainult realisatsiooni arendamise käigus kasutatud abiinfo maht oli mõlema realiseerimisviisi puhul piisav ning ka kood oli üldiselt arusaadav." Paljud andmebaasirakendused on veebirakendused. Nende vastu suunatud levinud rünnakumeetodiks on skriptisüstimine. Ründaja üritab anda veebirakendusele sisendi, et veebilehitseja hakkaks rakenduse kasutamisel käitama tema soovitud koodi. Halva tagamõttega sisend võib tulla nii lõppkasutaja poolt vormidesse sisestatult, kui ka andmebaasist, kus keegi on teinud pahatahtlikke andmemuudatusi. Vastumeetmed andmebaasi tasemel on: sisendi valideerimine (SQL-andmebaasis veergudel sobivad tüübid, CHECK kitsendused), vaba teksti väljade hulga vähendamine (SQL-andmebaasis klassifikaatori tabelid, välisvõtme kitsendused). Need on üks osa suuremast meetmete hulgast. Lugege (PHP) veebirakenduste sisendi valideerimise kohta täpsemalt siit. Kitsenduste andmebaasi tasemel deklaratiivsele jõustamisele tuleks mõelda kohe andmebaasi loomisel, mitte tagantjärgi. Deklaratiivset kitsendust ei saa andmebaasis luua (sõltuvalt andmebaasisüsteemist), kui andmebaasis juba olemasolevad andmed ei ole sellega kooskõlas. Kui luua alguses deklaratiivsete kitsendusteta andmebaas ja üritada hiljem deklaratiivseid kitsendusi lisada, siis võite põrkuda probleemiga, et andmebaasi on juba sattunud valideerimata andmeid ja mingit kitsendust ei saa luua. Selliste andmete andmebaasi sattumise põhjuseks võivad olla näiteks: vead rakenduste töös, rakenduste programmeerijate teadmatus ärireeglitest, mida peab andmete tasemel jõustama, lõppkasutaja hooletus. Siis on valikud: Hakata olemasolevaid andmeid parandama (võtab aega; sageli pole enam kelleltki küsida, millised peaksid olema paremad andmed). Parandamise järel saab jõustada deklaratiivsed kitsendused. Kui andmebaasisüsteem lubab, siis kasutada võimalust viia deklaratiivsed kitsendus seisundisse, mille kohaselt kontrollitakse uusi andmeid, kuid mitte andmebaasis juba olemasolevaid. Oracles tuleb selleks kitsendus viia seisundisse ENABLE NOVALIDATE ning PostgreSQLis seisundisse NOT VALID. Loobuda ühe või teise kitsenduse deklaratiivsest jõustamisest ning realiseerida kontroll kas andmebaasi tasemel rutiinides või trigerites või üldse ainult rakenduses. Lahendused 2 ja 3 võimaldavad jätta andmebaasis olemasolevad andmed selliseks nagu need on, kuid vähemasti kontrollida uusi andmeid. Kuna andmed on aluseks otsustele ja peaksid olema seega võimalikult täpsed, siis soovitan lahendusi 2 ja 3 nagu esmaabi, peale mida tuleks ikkagi jätkata punktis 1 toodud soovituse elluviimisega. Lõpetuseks - tänapäeval on populaarsust kasvatamas ärireeglite mootorid. Nende kasutamisel on sama eesmärk, mis kitsenduste andmebaasis defineerimisel - võtta süsteemi tööd juhtivad reeglid tarkvarast välja ning muuta need reeglid tsentraalselt hallatavaks. Reeglite muutmine mõjutab kõiki nende reeglite alusel töötavaid rakendusi. Kokkuvõttes ma jään enda juurde - kitsenduste andmebaasi tasemel jõustamine on kasulik. Alati on erandeid, aga need kinnitavad reeglit erandiga mitte kaetud juhtudel. Lugege palun lisaks seda artiklit! Mõttearendus andmebaasisüsteemi võimaluste kasutamise kohta PostgreSQL näitel. 2017. aastal avaldati teadusartikkel andmebaasirakenduste vastu suunatud ründemeetodist ACIDRain. See on ründemeetod, mis kasutab ära rakenduste nõrkust, mille korral saab rakendust manipuleerida nii, et selle antud korralduste alusel hakkab andmebaasisüsteem koostama mitteserialiseeritud tööplaane. Nende tööplaanide läbimise tulemusena satuvad andmebaasi olulised andmed, mis ei ole kooskõlas kitsendustega (invariantidega). Warszawski, T., Bailis, P., 2017. ACIDRain: Concurrency-related attacks on database-backed web applications. In Proceedings of the 2017 ACM International Conference on Management of Data. ACM. pp. 5–20. [WWW] http://www.bailis.org/papers/acidrain-sigmod2017.pdf Autorid uurisid 12 e-kaubanduse programmi, mida on kokku installeeritud üle kahe miljoni korra. Üle 60% miljonist kõige populaarsemast e-kaubanduse keskkonnast kasutavad ühte nendest programmidest. Uuring tuvastas nendes programmides kokku 22 kriitilist haavatavust, mida saab ACIDRain rünnakuga ära kasutada. Näiteks saab ründaja kasutada kinkekaarte üle etteseatud limiidi ja osta e-poest tasuta kaupu. ACIDRain rünnakute vältimises peavad arendajad tundma transaktsioone, lukustamist, transaktsioonide isolatsioonitasemeid ning oskama neid õiges kohas ja õigel viisil kasutada. Väidan, et paljud (kui mitte kõik) nendest haavatavustest ei oleks probleemiks, kui andmebaasi tasemel oleksid jõustatud deklaratiivsed kitsendused. Siis ei saa tekkida probleemi, et rakendustes on tulenevalt nende kitsenduste kontrolli ebapiisavast/halvast realiseerimisest võimalik nendest kitsendustest mööda minna. Enamike selliste kitsenduste deklaratiivseks andmebaasi tasemel jõustamiseks oleks vaja SQL-andmebaasides kasutada CREATE ASSERTION lauset, sest nende kitsenduste kontroll hõlmab sama tabeli erinevaid ridu või mitut tabelit. Kuigi CREATE ASSERTION lause on SQL standardis ette nähtud, ei toeta seda hetkel mitte ükski laiatarbe SQL-andmebaasisüsteem. Siin kirjutatakse kitsendustest PostgreSQL andmebaasisüsteemi näitel. Siin kirjeldatakse konkreetsete näidete varal, kuidas kitsenduste andmebaasis jõustamine aitab rakendusi lihtsustada. Siin on veel üks kitsenduste jõustamist pooldav ajaveebi sissekanne, mis on selle poolt, et rumala - kitsendusteta - andmebaasi tasemel tuleks luua nutikaid - kitsendustega - andmebaase.Roopärg (2022) bakalaureusetöös uuriti andmebaasis deklaratiivsete kitsenduste loomise mõju andmebaasirakenduste loomisele. Autor realiseeris PostgreSQLis ja MongoDBs erinevate disainidega andmebaasid (mõnel juhul esitati andmed JSON dokumentidena, mõnel juhul mitte) ja lõi nendele andmebaasidele andmebaasirakendused. Kõikides andmebaasides lõi ta võimalikult palju deklaratiivseid andmebaasi kitsendusi.  Üks tema järeldus oli, et andmekontrollide andmebaasis jõustamine lihtsustab andmebaasirakenduste loomist. Kuna ilma JSON dokumentideta PostgreSQL andmebaasis sai luua kõige rohkem andmekontrolle andmebaasis, siis sellele oli andmebaasirakenduse loomine kõige lihtsam. Kui rakenduse kasutaja andmemuudatus eksib andmebaasis deklareeritud kitsenduse vastu, siis kuvab rakendus andmebaasisüsteemi poolt tagastatavat veateadet. Selles osas oli PostgreSQL parem kui MongoDB, sest PostgreSQL veateated on kasutajasõbralikkuse vaatest paremad kui MongoDB poolt väljastatud veateated. Samuti võimaldab PostgreSQL keerukamate andmekontrollide loomist kui MongoDB.Kvaliteetsed otsused andmete põhjal vajavad kvaliteetseid andmeid. Andmekvaliteedil on palju erinevaid aspekte (vt siit jaotist 3.1.3). Andmebaasis kitsenduste jõustamine ei aita saavutada kvaliteeti igas aspektis, see pole hõbekuul, kuid kindlasti on nendest abi andmete täielikkuse, täpsuse ja unikaalsuse parandamisel. Erinevate Eesti riigiasutuste poolt koostatud "Andmete ja tehisintellekti valge raamat 2024-2030" kirjutab, et: "Tuleb juurutada põhimõte, et andmete kogumise hetkel rakendatakse koheselt kvaliteedi nõuded (st kogutud andmed ongi kohe kvaliteetsed ja tulevikus ei ole peale andmekogumist enam vaja andmeid ülemäära palju korrastada)." Kitsenduste andmebaasis jõustamine tähendabki, et kontroll toimub kohe andmete registreerimisel, mitte kunagi hiljem.  **Märksõnad:** triger, kitsendus, constraint, trigger, primaarvõti, välisvõti, unique, primary key, foreig key, check, not null, MongoDB, PostgreSQL ## Küsimus: Kas NoSQL andmebaasisüsteemides ja uue põlvkonna SQL-andmebaasisüsteemides (NewSQL süsteemid) saab luua vaateid, hetktõmmiseid ja rutiine? **Vastus:** Vaadetest, hetktõmmistest ja rutiinidest saab moodustada andmebaasi avaliku liidese (virtuaalse andmete kihi), läbi mille kasutada andmebaasi. Andmebaasiserveris talletatud rutiinide kasutamisele tuuakse nii pooltargumente kui vastuargumente (ignoreerib töökiirust - vaadake esimest kommentaari). Ka vaadete puhul võib täheldada (väikest) negatiivset mõju töökiirusele, kuid samas on kasutamisel ka mitmeid eeliseid.Kui selliste andmebaasiobjektide loomine on võimalik ka suhteliselt hiljuti turule tulnud süsteemides, siis järelikult tunnetatakse kasutajate nõudlust selle järgi.Vaatan näitena valikut populaarsetest NoSQL ja NewSQL süsteemidest. Vaatlen vaadete, hetktõmmiste e materialiseeritud vaadete ja kasutaja-defineeritud rutiinide (protseduurid, funktsioonid) loomise võimalust. Järgnevas nimekirjas nimetan võimalusi, mida SAAB vastavas andmebaasisüsteemis kasutada. Redis (NoSQL; võti-väärtus paaride andmemudel) Funktsioonid, mille abil saab realiseerida ka andmete muutmise protseduure MongoDB (NoSQL; dokumendipõhine andmemudel) Vaated Hetktõmmised Agregatsiooni torud (aggregation pipelines) protseduuride asemel JavaScriptis saab luua funktsioone Neo4j (NoSQL; graafipõhine andmemudel) Javas saab luua funktsioone ja protseduure Vaateid saab realiseerida protseduurina Cassandra (NoSQL; veeruperekondade andmemudel) Hetktõmmised Funktsioonid Mitme andmemuudatuse loogiliseks tervikuks koondamine (protseduuri kasutuse sagedane eesmärk) saab kasutada BATCH lauset InfluxDB (NoSQL; ajaseeriate andmebaasisüsteem) Ülesanded (tasks), mille abil saab realiseerida nii hetktõmmiseid kui andmete muutmise protseduure Varasema versiooni pidevpäringud (continuous queries), mis on sarnased hetktõmmistele, saab teisendada ülesanneteks CockroachDB (NewSQL) Vaated Hetktõmmised VoltDB (NewSQL) Hetktõmmised Protseduurid Funktsioonid **Märksõnad:** andmebaasi avalik liides, virtuaalne andmete kiht, NoSQL, vaade, hetktõmmis, virtuaalne tabel, materialiseeritud tabel, funktsioon, protseduur, rutiin, NewSQL ## Küsimus: Kas oleks mõistlik hoida andmebaasis asukoha andmeid aadressi ja riigi kombinatsiooni asemel koordinatidena? Kui jah, siis mis oleks sobivaim andmetüüp selleks(nii Oracles kui Postgresis)? **Vastus:** Kõik sõltub sellest, millisel otstarbel on plaanis neid andmeid kasutada. Kui tegemist on taustainfoga, mille alusel ei tehta täpseid otsinguid ja mida võibolla trükitakse kirjadele/arvetele, siis piisab veerust aadress. Tõstaksin riigi "sulgude ette" nii, et tabelis on aadressiandmete jaoks kaks veergu: aadress ja riigi_kood. riigi_kood on välisvõtme veerg, mis viitab klassifikaatori tabelile Riik. Tabelis Riik olevad andmed oleksid määratud rahvusvahelise klassifikaatoriga:  https://www.iban.com/country-codes Kui soov on teha aadressi alusel täpseid otsinguid, siis tuleb aadress "lahti lõhkuda" ning tükid erinevatesse tabelitesse/veergudesse salvestada. See pole triviaalne ülesanne. Näiteks Eestis on kasutusel kaheksa-tasemeline aadressiandmete süsteem (https://geoportaal.maaamet.ee/est/Andmed-ja-kaardid/Aadressiandmed-p112.html). O'Reilly digitaalse platvormi kaudu saab lugeda raamatut Blaha, M., 2010. Patterns of Data Modeling.Kuidas kasutada O'Reilly digitaalset platvormi? Peatükis 10 käsitletakse andmete modelleerimise arhetüüpe ning üks nendest on "Location" (jaotis 10.12). Eesti keele seletava sõnaraamatu kohaselt on arhetüüp "inimkonna kollektiivsest alateadvusest lähtuv püsistruktuur, mis teadvuses avaldub universaalse motiivi v. kujundina". Muinasjuttudele mõeldes on arhetüübiks näiteks noorim vend, kes lõpuks tapab lohe ning saab tasuks printsessi tähelepanu ja pool kunigriiki. Koordinaatide hoidmisel on mõtet, kui tahate näiteks asukohti kaardil kujutada. Andmebaasis koordinaatide ja koha-aadresside hoidmine ei välista teineteist. Nii Eesti aadressiandmete süsteem kui "Location" arhetüüp näevad ette ka ruumiandmete hoidmist koordinaatidena. Mis puudutab sobivaid veerge ja tüüpe, siis see sõltub kasutatavast koordinaatide süsteemist ja andmebaasisüsteemist. Näide: https://twcc.fr/ PostgreSQL ja Oracle on mõlemad objekt-relatsioonilised süsteemid ning lubavad defineerida uusi tüüpe - miks mitte ka geograafiliste koordinaatide jaoks. PostgreSQLis on mõned geomeetrilised tüübid/operaatorid süsteemi-defineeritud neid saab koordinaatide esitamiseks kasutada: https://stackoverflow.com/questions/1023229/spatial-data-in-postgresql Täpsemalt saate esitada ruumilise asukoha Point tüüpi väärtusena. Tavaks on esitada koordinaadid laiuskraad/pikkuskraad järjekorras, st Point tüüpi väärtuses võiks esimene koordinaat (arv) tähistada laiuskraadi ja teine pikkuskraadi.  Lisaks on vaja CHECK kitsendusi. Laiuskraad peab olema vahemikus -90 ja 90 (otspunktid kaasa arvatud) ja pikkuskraad peab olema vahemikus -180 ja 180 (otspunktid kaasa arvatud).Piirangud, et pikkuskraad ei tohi olla 0 ja laiuskraad ei tohi olla, on ebaõiged.Täpsema veateate huvides soovitan koordinaatide lubatud väärtuste vahemiku kontrollimiseks kahte eraldi kitsendust.CREATE TABLE Asukoht (asukoht_id SERIAL,koordinaat point NOT NULL,on_aktiivne BOOLEAN NOT NULL DEFAULT TRUE,CONSTRAINT pk_asukoht PRIMARY KEY (asukoht_id));ALTER TABLE Asukoht ADD CONSTRAINT chk_asukoht_koordinaat_laiuskraad CHECK (koordinaat[0] BETWEEN  -90 AND 90);ALTER TABLE Asukoht ADD CONSTRAINT chk_asukoht_koordinaat_pikkuskraad CHECK (koordinaat[1] BETWEEN -180 AND 180);INSERT INTO Asukoht (koordinaat) VALUES (point(41.40338, 2.17403));INSERT INTO Asukoht (koordinaat) VALUES (point(91.40338, 2.17403)); /*ERROR:  new row for relation "asukoht" violates check constraint "chk_asukoht_koordinaat_laiuskraad"DETAIL:  Failing row contains (2, (91.40338,2.17403)).*/Probleem tekib siis, kui soovin lisada tabelile kitsenduse, et aktiivsete asukohtade koordinaadid peavad olema unikaalsed. Sellise kitsenduse realiseerimine ebaõnnestub.CREATE UNIQUE INDEX ak_asukoht_aktiivne ON Asukoht (koordinaat) WHERE on_aktiivne=TRUE;/*ERROR:  data type point has no default operator class for access method "btree"HINT:  You must specify an operator class for the index or define a default operator class for the data type.*/ALTER TABLE Asukoht ADD CONSTRAINT ak_asukoht_aktiivneEXCLUDE (koordinaat WITH =) WHERE (on_aktiivne=TRUE);/*ERROR:  data type point has no default operator class for access method "btree"HINT:  You must specify an operator class for the index or define a default operator class for the data type.*/Võimalik lahendus oleks arvutatava veeru lisamine, kus oleks POINT tüüpi väärtuse tekstiliseks väärtuseks teisendamise tulemus.ALTER TABLE Asukoht ADD COLUMN koordinaat_tekst text GENERATED ALWAYS AS (CAST(koordinaat AS text)) STORED NOT NULL;Kitsenduse realiseerimine õnnestub.CREATE UNIQUE INDEX ak_asukoht_aktiivne ON Asukoht (koordinaat_tekst) WHERE on_aktiivne=TRUE;Rea lisamine ebaõnnestub.INSERT INTO Asukoht (koordinaat) VALUES (point(41.40338, 2.17403));/*ERROR:  duplicate key value violates unique constraint "ak_asukoht_aktiivne"DETAIL:  Key (koordinaat_tekst)=((41.40338,2.17403)) already exists.*/Rea lisamine õnnestub.INSERT INTO Asukoht (koordinaat, on_aktiivne) VALUES (point(41.40338, 2.17403), FALSE);Eelneva lahenduse probleem on, et koordinaadid salvestatakse kahekordselt.Selle asemel võiks seega kasutada lahendust, kus hoitakse laius- ja pikkuskraade kümnendmurruna. Siis kasutaksin: laiuskraad: DECIMAL(8,6) - PostgreSQL või NUMBER(8,6) - Oracle.pikkuskraad: DECIMAL(9,6) - PostgreSQL või NUMBER(9,6) - Oracle.Tabeli struktuuri parema loetavuse huvides võiksid olla laiuskraadi ja pikkuskraadi veerud kõrvuti ning laiuskraadi veerg eespool.Selliste veergude põhjal saab ka jõustada eelnimetatud kitsenduse. Kui peaksin hoidma kraade, minuteid ja sekundeid, siis võtaks iga selle komponendi jaoks kasutusele täisarvu tüüpi veeru. Lugege ka: https://stackoverflow.com/questions/6665894/what-is-the-best-way-to-store-geographic-coordinate-data-in-a-database Nii PostgreSQLi kui Oracle jaoks on olemas laiendused geograafiliste andmetega töötamiseks, kuid nendega ma kahjuks tuttav ei ole. PostgreSQL: PostGis (http://postgis.net/) Oracle: Oracle Spatial and Graph (https://docs.oracle.com/database/121/SPATL/toc.htm) **Märksõnad:** osaline unikaalne indeks, exclude kitsendus, point andmetüüp, decimal, numeric, arvutatav veerg, tüübiteisendus ## Küsimus: Kas uuendatavate vaadete (vaated, mille kaudu andmebaasisüsteem põhimõtteliselt lubaks INSERT/UPDATE lauseid käivitada) puhul on ikka vaja WITH CHECK OPTION kitsendust kasutada? **Vastus:** Jah on. Näiteks, kui juhataja rollis kasutaja näeb sellise vaate CREATE VIEW kinnitamata_tellimuste_vaade ASSELECT tellimuse_kood, tellimuse_seisundi_liik_koodFROM TellimusWHEREtellimuse_seisundi_liik_kood=2;kaudu kinnitamata tellimusi ja tal on vaate suhtes muutmisõigus, siis saaks ta ilma selle kitsenduseta käivitada lause: UPDATE kinnitamata_tellimuste_vaade SET tellimuse_seisundi_kood=3 WHERE tellimuse_kood='XX'; Selle tulemusena kaob tellimus XX kinnitamata tellimuste nimekirjast ära. Miks ma leian, et selline vaade vajab WITH CHECK OPTION kitsendust, mis keelab põhimõtteliselt sellise muudatuse tegemise (sõltumata kasutaja muutmisõigusest vaate suhtes)? See on põhimõtte küsimus. Süsteemi õpitavuse, kasutamise efektiivsuse, meeldejäävuse ja arusaadavuse seisukohalt on oluline, et süsteemi osade käitumine on ootuspärane, järjekindel ja võimalikult väheste eranditega - kokkuvõtlikult järgiks ortogonaalse disaini printsiipi. Olen ortogonaalse disaini printsiibist kirjutanud "Andmebaasid I" materjalides. Tarkvarakeel, mis on kavandatud ortogonaalse disaini printsiipi arvestades: pakub suhteliselt väikese hulga keelekonstruktsioone koos terviklike ja järjekindlate reeglitega nende konstruktsioonide kombineerimise kohta ning iga konstruktsioonide kombinatsioon on legaalne ja sisulist tähendust omav. SQL on näide keelest, mis paraku paljudes kohtades RIKUB ortogonaalse disaini printsiibi põhimõtteid ning nagu on näha käesolevast näitest, siis võimaldab ka luua süsteeme, mis omakorda seda printsiipi rikuvad. Baastabel, virtuaalne tabel e vaade, kitsendus, UPDATE ja INSERT operatsioon kuuluvad SQLi põhiliste konstruktsioonide hulka. Ortogonaalse disaini printsiibi mõtte kohaselt: INSERT ja UPDATE operatsioonid toimivad ühtemoodi nii baastabelitel kui virtuaalsetel tabelitel (seega, näiteks, kuna UPDATE lause baastabelist ridu ei kustuta, siis ei tee see seda ka virtuaalsete tabelite korral). Kitsendusi jõustatakse ühtemoodi nii baastabelitel kui virtuaalsetel tabelitel, st ei lubata nendes teha muudatusi, mis lähevad vastuollu neile defineeritud kitsendustega. Virtuaalse tabeli alampäringus olev piirang (predikaat) on selle tabeli kitsendus, mis ütleb, millistele tingimustele vastavad read selles tabelis sisalduvad. Tulles tagasi jutu alguses olnud näite juurde, siis siin tuleks lisaks vaatele teha funktsioon, mille sisuks on etteantud koodiga tellimuse kinnitamine. Kasutajale antakse õigus käivitada funktsiooni, kuid ei anta UPDATE õigust vaate suhtes. Seega vaade on praktikas kasutusel andmete lugemiseks ning funktsioon selleks, et seisundit muuta. Funktsioon muudab andmeid otse baastabelis Tellimus. Sellise lahenduse põhjenduseks on SQLi suured piirangud uuendatavatele vaadetele (mis on kõigele lisaks erinevates andmebaasisüsteemides erinevad). Seetõttu on otstarbekas vaadete uuendamise võimalust (andmete muutmine vaate kaudu) praktikas mitte kasutada. Põhimõtte pärast peaks sellisel vaatel minu arvates aga siiski olema WITH CHECK OPTION kitsendus. ## Küsimus: Kas võin eeldada, et Eesti isikukood on unikaalne identifikaator? **Vastus:** Eesti e-riigi loogika eeldab, et see on unikaalne. Samas tuleb välja, et unikaalsus ei ole mineviku möödalaskmiste tõttu tagatud. Huvitav ülevaade Eesti isikukoodi loomise taustast ja kaalutlustest (originaal pole enam saadaval, kuid ajamasinas on see säilinud). Muuhulgas väärib tähelepanu tsitaat: Although it has served Estonia well, the system was not perfect. To the extent that, in fact, in the early days several people received the same identification code and it was too deep in the registries before the mistake was discovered. Thus, technically, the id-code in Estonia can not be assumed to be unique. Hea näide, miks on parem asju kohe hästi teha, mitte loota sellele, et hiljem midagi parandada õnnestub. ## Küsimus: Kuidas kontrollida regulaaravaldisega, et string tohib sisaldada ainult numbreid ning suurtähti (A-Z)? **Vastus:** Järgnevaid lauseid tuleb käivitada PostgreSQLi andmebaasisüsteemis. Soovi korral saate näiteks kasutada DB Fiddle keskkonda.Katsetus 1 Regulaaravaldis: '[A-Z0-9]+' Kuidas kontrollida seda regulaaravaldist PostgreSQLis? SELECT 'EST?12'~'[A-Z0-9]+' AS tulemus; ja SELECT 'est12'~'[A-Z0-9]+' AS tulemus; annavad mõlemad tulemuseks TRUE, sest kontrollitakse, et stringis sisalduks vähemalt üks märk (seda näitab +), mis kuulub märkide klassi [A-Z0-9]. Seega see regulaaravaldis seda ülesannet ei lahenda. Katsetus 2 Regulaaravaldis: '^[A-Z0-9]+$' ^ tähendab stringi algust $ tähendab stringi lõppu Stringi alguse ja lõpu vahel tohivad olla vaid märkide klassi kuuluvad märgid. Kuidas kontrollida seda regulaaravaldist PostgreSQLis? SELECT 'EST?12'~'^[A-Z0-9]+$' AS tulemus; ja SELECT 'est12'~'^[A-Z0-9]+$' AS tulemus; annavad mõlemad tulemuseks FALSE. SELECT 'EST12'~'^[A-Z0-9]+$' AS tulemus; ja SELECT 'est12'~*'^[A-Z0-9]+$' AS tulemus; annavad mõlemad tulemuseks TRUE. SELECT 'est12'~*'^[A-Z0-9]+$' AS tulemus; tulemuseks on TRUE, sest ~* operaator teostab tõstutundetut vastavuse kontrolli. ## Küsimus: Kuidas oleks termin "paks andmebaas" inglise keeles ja kust selle lähenemise kohta veel infot saaks? **Vastus:** Sellise andmebaasi kohta võib ka öelda "jäme andmebaas". Otsetõlge oleks "thick database" või thickDB (sõna "fat" võib tänapäeval äkki kedagi solvata), kuid kasutatakse ka termineid "smart database" või "smartDB". Eesti keeles oleks see "nutikas andmebaas" või "arukas andmebaas".Järgnevalt on mõned viited allikatele. Paljud näited põhinevad Oraclel, kuid see tuleb minu arvates lihtsalt Oracle andmebaasisüsteemi ja PL/SQL keele populaarsusest. Muide, Oracle 23c lisandus võimalus luua andmebaasis talletatud rutiine JavaScript keeles. Juba varem oli võimalus luua selliseid rutiine ka C või Java keeles. Oracle andmebaasisüsteemi sisse ehitatud mitmekeelsuse mootor (Multilingual Engine) võib tulevikus võimalda nende keelte hulka veelgi suurendada. Erinevate keelte kasutamise võimalus pole mõeldud PL/SQL keele asendamiseks, vaid teistsuguse teadmiste pagasiga uutele arendajatele täiendava võimaluse andmiseks. Sarnaselt saab ka näiteks PostgreSQLis kirjutada rutiine erinevates protseduursetes keeltes (ning lisaks SQL keeles) ja andmebaasisüsteemis on mehhanism uute keelte toe lisamiseks.Siin on allikaid nutika/paksu andmebaasi kohta, kus andmebaasisüsteemi näiteks on Oracle. SmartDB: A Database Centric Approach to Application Development (ettekande pdf) NoPLSql and Thick Database Approaches with Toon Koppelaars (YouTube video) NoPlsql versus ThickDB The SmartDB Resource Center The Helsinki Declaration (IT-version) Samasugune lähenemine on loomulikult võimalik ka teistes andmebaasisüsteemides, mis toetavad andmebaasiserveris talletatud rutiine, nagu näiteks PostgreSQL. This is the Golden Age of the Thick Database **Märksõnad:** paks andmebaas, jäme andmebaas, nutikas andmebaas, arukas andmebaas, thick database, thickDB, smart database, smartDB ## Küsimus: Kuidas sobitub Tallinna Tehnikaülikooli andmebaaside kursustes õpitud andmebaaside projekteerimise lähenemine erinevate arendusmetoodikatega? **Vastus:** Leian, et seda on võimalik erinevate metoodikatega (sh paindmetoodikatega) kenasti koos kasutada. Artefaktidel põhinev äriprotsesside modelleerimine kasutab süsteemide kirjeldamiseks (sh protsesside modelleerimiseks) andmekeskset lähenemist. Sarnasel andmekesksel lähenemisel põhineb ka Tallinna Tehnikaülikooli andmebaaside alastes kursustes (Andmebaasid I ja Andmebaasid II) kirjeldatud andmebaaside projekteerimise metoodika. Andmekeskne lähenemine äriprotsesside/süsteemide modelleerimisele ei ole uus idee nagu võiks Wikipedia artiklit lugedes mulje jääda (kõik viidatud artiklid on 2000-ndatest). Lugege selle kohta: Sanz, J.L., 2011. Entity-centric operations modeling for business process management- a multidisciplinary review of the state-ofthe-art. In IEEE 6th International Symposium on Service Oriented System Engineering (SOSE). IEEE. pp. 152–163. [WWW] https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=8941562496e89350b82a252556eb2ff9f7353c93 Tegelikult tegeleti sellega palju 1980-ndatel ja 1990-ndatel. Seoses objektorienteeritud analüüsi ja disaini populaarsuse kasvuga huvi vahepeal vähenes, kuid artefaktikeskne äriprotsesside modelleerimine on selle huvi taastekitanud. ## Küsimus: Kuidas töötab objekt-orienteeritud andmebaas (object-oriented database (OODBMS)), miks peeti neid vahepeal nõnda lootustandvateks ning miks ei ole need siiski oodatud populaarsust saavutanud? **Vastus:** Objektorienteeritud andmebaasisüsteemidelt oodati/loodeti: võimekust kasutada "keeruka struktuuriga" objekte, võimalust kasutada andmetüüpe, mida tollal SQL-andmebaasisüsteemid ei võimaldanud kasutada, OO programmeerimiskeeles kirjutatud tarkvara (said tuule tiibadesse 1980-ndatel) poolt andmete püsisalvestamise ja püsisalvestatud andmete lugemise lihtsamaks muutumist. Aja jooksul ei tekkinud ühtset ja laialt kasutusele võetud standardit objektorienteeritud andmemudeli ja andmebaasikeele kohta. Seega iga süsteem tegi asju omamoodi ja laialdaseks kasutuselevõtuks see häid tingimusi ei loonud. Muide, kui graafipõhised andmebaasisüsteemid välja jätta (graafipõhise andmebaasikeele jaoks luuakse rahvusvahelist standardit), siis sama oht ähvardab ka NoSQL süsteeme. Üldiselt võttes on objektorienteeritud andmebaas nagu objektorienteeritud programmeerimiskeeles kirjutatud programmi käepikendus. Selle põhiline ehitusplokk on klass. Andmeid esitatakse klassi kuuluvate objektidena ja seoseid nende objektide vaheliste viitadena (pointers).Miks ei saanud populaarseks? Puudus tugev matemaatiline aluspõhi nagu see on relatsioonilisel mudelil. Ei tekkinud ühtset arusaama, mis on objektorienteeritud andmemudel. Ei tekkinud andmebaasikeele standardit. Andmebaasisüsteemid tegid igaüks asju ise moodi ja palju vajalikke funktsionaalsuseid oli puudu. Konkurendid (SQL) suutsid kiiresti kohaneda ja SQL standardi versioonis SQL:1999 rikastati objektorienteeritud võimalustega. Sellest ajast räägitakse SQList kui objekt-relatsioonilisest andmebaasikeelest. Tänu sellele saab SQLis luua tüüpe ja kasutada neid tabelite ning veergude defineerimisel. Peale esialgset haipi saadi aru, et paljusid andmeid ongi lihtsam SQL-andmebaasis esitada ja neid seal kasutada. Tänapäeval on objektorienteeritud andmebaasisüsteemid endiselt turul, kuid need ei ole populaarsed. Neid kasutatakse näiteks disainide (keeruka struktuuriga objektid) haldamiseks. SIIT saab eesti keeles pikemalt lugeda objektorienteeritud andmebaasisüsteemide ja SIIT objekt-relatsiooniliste andmebaasisüsteemide kohta.Mõned OO-andmebaasisüsteemid pakuvad SQLi kui ühte võimalikku keelt, mille abil kasutada andmebaasis olevaid andmeid. Sellise andmebaasisüsteemi näide on InterSystems CACHÉ. See kasutusvõimalus lähtub eeldusest, et klass=tabel. ## Küsimus: Kui pikad võivad olla isikunimed ja millist väljapikkust kasutada isikunimede puhul andmebaasis? **Vastus:** Erinevates kultuurides on isikunimedel erinevaid komponente (lugege selle kohta lõputööst). Levinud lahenduseks andmebaasides on hoida isikunime kas ühes veerus või kahes veerus (eesnimi/first_name/given_name ja perenimi/last_name/surname). Valdavalt on isikunimed üpris lühikesed. Näiteks Eestis Statistika kirjutab eesnimedest: "Taasiseseisvumise perioodi iseloomustab ka mitme nime panek lastele. 2000-ndate alguses sai ligi viiendik tüdrukutest ja pisut vähem poisse nime, mille pikkus oli 10 või rohkem tähemärki. Eelmisel kümnendil hakkas nimede pikenemise trend pöörduma. Populaarsemaks muutusid taas kuni 5-tähelised nimed (praguseks 40% nimedest) ja vähenes ülipikkade nimede panek lastele." 2021. aastal sündinud ja hetkel Eestis elavate naissoost isikute (ees)nimedest moodustasid nimed pikkusega 15 või rohkem tähte 2.15%. Meessoost isikutel oli see vastavalt 2.16%.Teadusartiklis Federating patients identities: the case of rare diseases käsitleti haruldaste haiguste andmebaasis olevate andmete anonümiseerimist, et need oleksid teadlastele kättesaadavad. Uuringu käigus leiti andmebaasi põhjal 280000 isiku ees- ja perenime mediaanpikkus. Eesnime mediaanpikkus oli 6.5 ja perenime mediaanpikkus oli 7.1. Artiklis esitatud joonise järgi jäid pikimad eesnimed alla 20 märgi ja perenimed alla 30 märgi.USA rahvaloenduse andmetel oli 53% inimeste perenime pikkus 5-7 märki. Samas on USA-st ka näiteid ülipikkadest nimedest.Guinnessi rekord pikima sünnitunnistusel oleva nime kohta kuulub USA kodanikule, kelle eesnimi on 1023 märki, keskmine nimi 36 märki ja perenimi 8 märki pikk. Maailma pikimas perenimes oli üle 600 märgi (nimest on erinevaid versioone). Samas ametlikes dokumentides kasutas ta 35 märgi pikkust perenime versiooni. See allikas väidab, et Guinnessi rekordite raamat ei võta enam vastu pikima nime avaldusi, et mitte tekitada vanemates kiusatust liiga pikki nimesid anda. Siin on veel näiteid väga pikkadest nimedest.Enamasti ei sea riigid juriidilisi piiranguid nime pikkusele. Siiski märgitakse siin, et mõned USA osariigid piiravad nimes lubatud märkide arvu tulenevalt inimeste üle arve pidamiseks mõeldud tarkvara piirangutest. Enamikes osariikides sõnavabadusele viidates selliseid piiranguid ei ole.Eesti nimeseadus nime pikkusele piirangut ei sea, kuid annab ametnikele kaalutlusõiguse (nimi peab olema kooskõlas heade kommetega).Internetis leidub hulgaliselt soovitusi eesnime ja perenime maksimaalse väljapikkuse kohta. Ühisnimetaja on, et soovitatud pikkused on suhteliselt väikesed. Näiteks siin pakutakse 35, 50, 64, 255 ja siin pakutakse perenimele 35, 50, 100. Ka erinevad programmid kasutavad suhteliselt lühikesi väljapikkuseid (näiteks siin eesnimi 40, perenimi 80). Liiga suure lubatud väljapikkuse probleemideks on see, et välja on lihtsam lisada ründeskripti (turvalisus) ja kasutajaliideses tuleb sisestusvälja näidata suuremana kui valdava enamiku nimede puhul on vajalik. Turvalisuse probleem tuleb eriti esile süsteemi kasutajaks registreerimise vormil, kus on ees- ja perenime väljad ja mis on mõeldud kasutamiseks kõigile soovijatele.Eelnevast lähtuvalt soovitan ees- ja perenime veergudel maksimaalseks väljapikkuseks 50. **Märksõnad:** isikunimi, eesnimi, perenimi, väljapikkus, isikunimi, isikunimed ## Küsimus: Kui soovin kontrollida, et nimi tohib sisaldada vaid tähti ja tühikuid, siis kas sobib selline regulaaravaldise muster: '^([a-zA-Z]|[[:space:]])+$' ? **Vastus:** Ei, kahjuks ei sobi, sest Te välistate nimedes näiteks täpitähed. Märkide hulga [a-zA-Z] asemel tuleks kasutada märkide klassi [:alpha:]. PostgreSQL SELECT 'Õnne Pärl'~'^([a-zA-Z]|[[:space:]])+$' AS tulemus; Tulemus: FALSE SELECT 'Õnne Pärl'~'^([[:alpha:]]|[[:space:]])+$' AS tulemus; Tulemus: TRUE Oracle DECLARE result BOOLEAN; BEGIN result:=REGEXP_LIKE('Õnne Pärl', '^([a-zA-Z]|[[:space:]])+$'); IF (result=true) THEN dbms_output.put_line('TRUE'); ELSE dbms_output.put_line('FALSE'); END IF; END; / Tulemus: FALSE DECLARE result BOOLEAN; BEGIN result:=REGEXP_LIKE('Õnne Pärl', '^([[:alpha:]]|[[:space:]])+$'); IF (result=true) THEN dbms_output.put_line('TRUE'); ELSE dbms_output.put_line('FALSE'); END IF; END; / Tulemus: TRUE Märkide klassid. Eraldi küsimus on, kas isikunimede puhul on sellist kontrolli vaja? Leian, et ei ole, sest tulenevalt kultuurilistest eripäradest võivad nimed olla väga eripalgelised. ## Küsimus: Kui veebipõhises andmebaasirakenduses on vaja esitada päringu tulemusi lehekülgede kaupa, siis kuidas oleks kõige parem vastavat päringut andmebaasis teha? **Vastus:** Sellest kirjutatakse pikemalt SIIN, SIIN ja SIIN.Seal tuuakse välja kaks lahendust: OFFSET'i e nihke kasutamine (nihke meetod) Päringu tingimuse sellisel viisil seadmine, et OFFSET'i ei ole vaja kasutada (otsingu meetod). OFFSET'i kasutamisel on mitmeid puuduseid, millest üheks on jõudluse pidev langus, mida kaugemaid lehekülgi tulemuse algusest kasutaja vaatab. Tegemist on ühe töökiiruse antimustri ilminguga.Järgnev töökiiruse näide põhineb PostgreSQL'il ja katsetus on tehtud PostgreSQL 16-ga. Tabelis Hcv (tervishoiuasutuse külastus) on 1_000_000 rida. Soovin kõigepealt leida kõik külastused sorteerituna id väärtuse järgi kasvavalt ja väljastada andmed 10-rea suuruste portsudena.Kõigi järgnevate lausete täitmisel loetakse andmebaasisüsteemi poolt primaarvõtme veerule (health_care_visit_id) loodud indeksit (index scan operatsioon), sest selle lehtedes on võtmeväärtused sorteeritud. Iga tabeli rea kohta loetakse indeksipuu leheks olevat plokki ja sealt leitud info alusel tabeli rea andmeid sisaldavat plokki.SELECT *FROM HcvORDER BY health_care_visit_idOFFSET 0FETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 0.1 ms, loetakse 10 rida.SELECT *FROM HcvORDER BY health_care_visit_idOFFSET 10_000FETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 2.6 ms, loetakse 10_010 rida.SELECT *FROM HcvORDER BY health_care_visit_idOFFSET 999_990FETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 344 ms, loetakse 1_000_000 rida.Seega nihke abil portsude leidmiseks otsib süsteem ka kõik need read, mis jäävad tulemuseks olevas ridade hulgast nihkest ettepoole. Seega, mida kaugemale tulemuste väljastamisega liikuda, seda aeglasemaks muutub päring.Alternatiivne ja parema töökiirusega lahendus leiab vajaliku ridade hulga WHERE klausli abil. Ka järgnev lahenduse korral kasutatakse päringu täitmiseks primaarvõtmele loodud indeksit, kui sõltumata sellest, kas soovitav ports on tulemusteks oleva ridade hulga alguses või lõpus on lause täitmiseks loetavate andmete hulk ja seega ka lause täitmise kiirus ühesugune.SELECT *FROM HcvWHERE health_care_visit_id>0ORDER BY health_care_visit_idFETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 0.05 ms, loetakse 10 rida.SELECT *FROM HcvWHERE health_care_visit_id>999990ORDER BY health_care_visit_idFETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 0.03 ms, loetakse 10 rida.Selle lahenduse korral peab portse sooviv tarkvara meeles pidama, millised olid kõige viimased andmed, mida see sai ning kasutama seda päringu tingimuses. Näiteks teise päringu korral teadis tarkvara, et kõige viimane visiit, mille andmeid see kuvas oli identifikaatoriga 999_990.Sama põhimõte kehtib ka siis, kui sorteeritakse mõne muu veeru põhjal kui võtmeveerg.SELECT *FROM HcvORDER BY from_date, patient_idOFFSET 0FETCH FIRST 10 ROWS ONLY;Päringu täitmiseks toimub tabeli täielik läbiskaneerimine, sest pole indeksit, kus oleks samad veerud ja samas järjekorras kui ORDER BY klauslis. Lause täitmiseks kulub 112 ms.SELECT *FROM HcvORDER BY from_date, patient_idOFFSET 999990FETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 545 ms.Loon indeksi, kus on veerud, mida kasutatakse sorteerimisel ning need on samas järjekorras kui ORDER BY klauslis.CREATE INDEX idx_hcv_date_patient ON Hcv (from_date, patient_id);ANALYZE;Peale seda kasutati eelnimetatud kahe lause täitmiseks indeksit (index scan). Esimese lause täitmiseks kulub 0.79 ms ja teise lause täitmiseks 1101 ms. Nii et indeksist oli kasu, kuid saaks veel paremini. Kui kasutada portsudeks jagamisel otsingu meetodit, siis on töökiirus palju parem. Ka mõlema järgneva lause täitmiseks kasutatakse eelnevalt loodud indeksit.SELECT *FROM HcvWHERE (from_date, patient_id)>('2000-10-13', 30017)ORDER BY from_date, patient_idFETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 0.139 ms.SELECT *FROM HcvWHERE (from_date, facility_id)>('2014-10-12', 95334)ORDER BY from_date, facility_idFETCH FIRST 10 ROWS ONLY;Lause täitmiseks kulub 1.278 ms. **Märksõnad:** pagineerimine, lehekülgedeks jagamine, ramp, töökiirus, jõudlus, limit, offset, pagination ## Küsimus: Kust saada infot andmebaasi testimiskeskse arendamise kohta? **Vastus:** Raamatust Guernsey III, M., 2013. Test-Driven Database Development. Unlocking Agility. Addison-Wesley. 315 p.Seda saab lugeda O'Reilly digitaalse platvormi kaudu elektrooniliselt. Kuidas kasutada O'Reilly digitaalset platvormi? ## Küsimus: Miks peaks eelistama trigerite puhul tingimuse kirjutamist päises olevasse WHEN klauslisse, selle asemel, et kirjutada see kehandis olevasse IF lausesse? **Vastus:** Stackoverflow arutelus pakub kasutaja Elad ühe ülesande lahendusena välja variandid A ja B. Variandi A korral on tingimus trigeri kehandis IF klauslis. Variandi B korral on tingimus trigeri päises WHEN klauslis. Trigereid on seetõttu kaks, mitte üks. Tõsi on, et muudatuste tegemiseks on variandi A korral mõnikord vaja käivitada vähem lauseid kui variandi B korral. Kui ma tahan muuta trigeri loogikat, siis tuleb käivitada kaks lauset: DROP TRIGGER ja CREATE TRIGGER. Kui terve loogika on trigeri funktsioonis siis CREATE OR REPLACE FUNCTION lause on muudatuseks piisav. Kuid sama saab ka öelda B kohta - kui tahan näiteks lõpetada reageerimise UPDATE sündmusele, siis DROP TRIGGER ja CREATE OR REPLACE FUNCTION lausete asemel piisab DROP lausest. Variant B eeliseks on, et IF lausete sees olevat koodi ei dubleerita ja seetõttu on ka funktsioon lihtsam. Minu arvates on R.C. Martini puhta koodi raamatu halbade lõhnade kataloogi (peatükk 17) kohaselt lahendusel A järgmised halvad lõhnad: G5: Duplication G30: Functions Should Do One Thing (Kuidas kasutada O'Reilly digitaalset platvormi?)Lisaks võtab variant A andmebaasisüsteemilt võimaluse teostada optimeerimist, mille kohaselt käivitatakse ja läbitakse trigeri funktsioon ainult siis, kui selleks on tõesti vajadus (st tingimused on täidetud). Lõpetuseks on variant B ka veidi paremini kooskõlas üldise relatsiooniliste/SQL-andmebaaside ideoloogiaga, mille kohaselt tegevused toimuvad indiviidide hulkadega, mitte üksikute indiviididega. Variandile A vastab algoritm: FOR EACH huvipakkuv objekt o IF o.rahuldab_tingimust o.tee_tegevus END IF; END; ja variandile B vastab algoritm: FOR EACH huvipakkuv objekt o WHERE o.rahuldab_tingimust o.tee_tegevus END; **Märksõnad:** triger, trigerid, puhas kood, deklaratiivne, imperatiivne ## Küsimus: Miks peaks tabeliga seotud kitsenduse või indeksi nimi sisaldama tabeli nime? **Vastus:** Hea praktika on sellistes nimedes tabeli nime kasutada. Üldine põhimõte on, et tabeli nimi aitab tagada kitsenduse/indeksi nime unikaalsust skeemi piires. Miks on nime unikaalsus skeemi piires vajalik? Miks kasutada indeksi nimes tabeli nime? See vähendab nimekonfliktide tekkimise võimalust. Indeksi nimi peab olema nii PostgreSQLis kui Oracles skeemi piires unikaalne. Erinevates samas skeemis olevastes tabelites võib olla sama nimega veerge. Kui annate selliste veergude korral indeksitele või kitsendustele, millega koos luuakse automaatselt indeks (PRIMARY KEY, UNIQUE, PostgreSQLis ka EXCLUDE) nime, mis sisaldab ainult tabeli veeru nime, siis kutsute sellise nimekonflikti ise esile. Nimekonflikti esilekutsunud lause (CREATE INDEX, CREATE TABLE, ALTER TABLE) jääb täitmata. Kui indeksi nimes ei ole tabeli nime, siis halvendab see SQL andmekäitluskeele lausete täitmisplaanide loetavust. Miks kasutada kitsenduse nimes tabeli nime? Oracles peavad kitsenduste nimed olema skeemi piires unikaalsed. Arvestades võimalusega, et erinevates sama skeemi tabelites võib olla sama nimega veerge, eeldab nimetamisskeem, mis tagab sisukad unikaalsed ja ühetaolised nimed, tabeli nime kasutamist kitsenduse nime osana. PostgreSQL on kitsenduste nimetamisel liberaalsem. PRIMARY KEY, UNIQUE ja EXCLUDE kitsenduste nimed peavad olema unikaalsed skeemi piires. Nende kitsenduste toetuseks luuakse indeks ja indeksi nimi peab olema skeemi piires unikaalne. Erinevates tabelites võib olla sama nimega CHECK ja FOREIGN KEY kitsendusi. Ühes ja samas tabelis ei tohi olla sama nimega CHECK ja FOREIGN KEY kitsendust. PostgreSQLis peaks PRIMARY KEY, UNIQUE ja EXCLUDE kitsenduste nimedes kasutama tabeli nime tulenevalt indeksitega seoses mainitud punktist 1. PostgreSQLis peaks FOREIGN KEY (ning tulevikku silmas pidades ka CHECK kitsenduste) nimed olema unikaalsed, et oleks mugavam kasutada seda lauset: https://www.postgresql.org/docs/current/sql-set-constraints.html " Because PostgreSQL does not require constraint names to be unique within a schema (but only per-table), it is possible that there is more than one match for a specified constraint name. In this case SET CONSTRAINTS will act on all matches." Unikaalsed kitsenduste nimed aitavad paremini aru saada veateadetest. Unikaalsete kitsenduste nimede alusel on parem skriptifailist või päringuga andmebaasi süsteemikataloogist huvipakkuva kitsenduse kirjeldus üles leida. **Märksõnad:** indeks, kitsendus, nimetamine ## Küsimus: Miks peavad ka rakenduste programmeerijad andmebaase hästi tundma? **Vastus:** Väga eluline näide (seostub teemaga 6 - transaktsioonid ja lukustamine). 2017. aastal avaldati rahvusvahelisel tippkonverentsil teadusartikkel, kus sellist tüüpi rünnakute tagamaid täpsemalt avati ning uuriti nende esinemise võimalust 12 e-kaubanduse programmi põhjal. Warszawski, T., Bailis, P., 2017. ACIDRain: Concurrency-related attacks on database-backed web applications. In Proceedings of the 2017 ACM International Conference on Management of Data. ACM. pp. 5–20. [WWW] http://www.bailis.org/papers/acidrain-sigmod2017.pdf Autorid nimetavad sellist tüüpi rünnakut ACIDRain. See on ründemeetod, mis kasutab ära rakenduste nõrkust, mille korral saab rakendust manipuleerida nii, et selle antud korralduste alusel hakkab andmebaasisüsteem koostama mitteserialiseeritud tööplaane. Uuritud 12 e-kaubanduse programmi on installeeritud üle kahe miljoni korra. Üle 60% miljonist kõige populaarsemast e-kaubanduse keskkonnast kasutavad ühte nendest programmidest. Uuring tuvastas nendes programmides kokku 22 kriitilist haavatavust, mida saab ACIDRain rünnakuga ära kasutada. Näiteks saab ründaja kasutada kinkekaarte üle etteseatud limiidi ja osta e-poest tasuta kaupu. ACIDRain rünnakute vältimises peavad arendajad tundma transaktsioone, lukustamist, transaktsioonide isolatsioonitasemeid ning oskama neid õiges kohas ja õigel viisil kasutada. 2015. aastal avaldati rahvusvahelisel tippkonverentsil teadusartikkel, kus kirjeldati Ruby on Rails raamistikus loodud 67 avatud lähtekoodiga rakenduse uurimise tulemusi. Bailis, P., Fekete, A., Franklin, M. J., Ghodsi, A., Hellerstein, J. M., Stoica, I., 2015. Feral concurrency control: An empirical investigation of modern application integrity. In Proceedings of the 2015 ACM SIGMOD International Conference on Management of Data. ACM. pp. 1327-1342 [WWW] http://www.bailis.org/papers/feral-sigmod2015.pdf Uuring keskendus rakenduse tasemel jõustatud andmete kontrollidele. Uuringu tulemusena selgus, et 13% uuritud kontrollidest olid ebapiisavad (st lubasid andmebaasi kitsendusega vastuolus olevaid andmeid), sest ei arvestanud andmete samaaegse kasutamise võimalusega. Artikli järeldustes tõdeti: "Andmete samaaegse kasutamise reguleerimise lahenduste sisseehitamine rakendusraamistikesse või üksikutesse rakendustesse on kallis, veaohtlik ja raske ettevõtmine, mis eirab andmebaaside valdkonnas aastakümneid sellel suunal tehtud tööd. Kuigi see lähenemine on piisav, et tagada meie analüüsitud süsteemide puhul umbes 87% kitsenduste korrektne jõustamine, võib ülejäänute puhul andmete kontrollimine paljudes kaasaegsete ORMides viia kitsendustele mittevastavate andmete registreerimiseni." Seega rakenduste looja peaks oskama selle võimalusega arvestada ning teadma ka seda, kuidas kitsenduste andmebaasi tasemel jõustamine tema tööd lihtsamaks teeb nagu kirjeldatakse näiteks siin ja siin. Siis ei ole andmebaasis kitsenduste jõustamine tema jaoks enam "veider trikk". Järgneva kohta võivad küünilised programmeerijad öelda, et palju koodi ja pärmina paisuvad arenduste hinnad annavad neile tööd ja leiba. Kuid kindlasti on see suur probleem ARVETE MAKSJATELE (lõpuks tuleb kogu raha ikkagi kas maksumaksja või organisatsiooni pakutava toote/teenuse ostja taskust). Tänapäeva tarkvaraprojekte iseloomustavad üle kokkulepitud tähtaegade minek ning arenduseks kulunud summade kasv. Pole mingi ime, kui süsteem, mis algselt pidi maksma üks miljon Eurot, läheb maksma 10 miljonit Eurot või rohkem. Näideteks on Sotsiaalkindlustusameti infosüsteemi SKAIS2 arendus Eestis ja Obamacare veebilehe arendus USAs. Selle põhjuseks on raiskamine ning sellest kirjutab pikemalt oma raamatus Dave McComb. See näide pole seotud andmebaasidega, kuid on siiski tähelepanuväärne näide üle võlli kulutustest (raiskamisest) lihtsale tarkvarale. Suured kulud tulevad tarkvara asjatust keerukusest. McComb pakub välja tarkvara keerukuse leidmise valemi: keerukus = rakenduste arv * andmebaasi skeem (skeemi elementide arv - nt tabelite ja veergude arv) * rakenduste lähtekood (koodiridade arv) skeemi kohta Keerukuse vähendamiseks tuleks nende näitajate väärtuseid vähendada. McComb kirjutab, et kui kahte nendest vähendada poole võrra, siis väheneb keerukus 75% ja kui kõiki kolme vähendada poole võrra, siis väheneb keerukus 83%. "Andmebaasid I" õppeaines räägitud allsüsteemideks jagamine aitab hoida rakenduste arvu kontrolli all, väldib funktsionaalsuse dubleerimist erinevates rakendustest (igale funktsionaalsele allsüsteemile hakkab vastama rakendus, mis tänapäeva mobiilses maailmas võib isegi olla äpp) ja andmete dubleerimist erinevates andmebaasi alamosades e registrites. Hästi disainitud e kavandatud andmebaas (kus on läbimõeldud ja hästi koostatud andmestruktuurid) muudab rakenduse tegemise lihtsamaks ja vähendab vajamineva koodi hulka. Halvasti disainitud andmebaas, vastupidi, suurendab vajamineva koodi hulka. Hästi disainitud tähendab muuhulgas, et andmebaasis, kus on vaja üksikuid fakte lisada, muuta ja kustutada (operatiivandmete andmebaas), on võimalikult vähe andmete liiasust (vt andmebaasi normaliseerimine ja ortogonaalse disaini printsiip). Kui näiteks kliendi andmeid korratakse üle erinevate andmestruktuuride, siis kasvab skeemi suurus ja skeemi jaoks vajaliku rakenduse koodi hulk ning see omakorda kasvatab keerukust. Kui andmestruktuur ei ole kõrge astmeni normaliseeritud ja seal on palju andmete liiasust, siis suureneb andmete muutmiseks vajaliku koodi hulk ja see kasvatab keerukust. Rääkimata sellest, et suurem andmete hulk vähendab andmete muutmise operatsioonide täitmiskiirust. Ärireeglite kontroll andmebaasi tasemel vabastab vajadusest neid kontrolle korduvalt ja erinevates rakendustes realiseerida ja seega vähendab vajamineva koodi hulka. Kui on täiesti kindel, et andmebaasis olevad andmed vastavad teatud reeglitele (st nende reeglite kontroll toimub andmebaasi tasemel), siis saab andmete küsimiseks kirjutada lihtsamaid päringuid ja andmebaasisüsteem suudab teatud päringuid kiiremini täita. Deklaratiivne andmebaasikeel (nagu SQL andmekäitluskeel) on väga võimas ning suhteliselt väikese koodi hulgaga saab lahendatud vägagi keerulised andmete otsimise või muutmise ülesanded. Võrdluseks, sama ülesande lahendamine rakenduse tasemel imperatiivselt (süsteemile samm‑sammult tegevusi ette kirjutades), nõuaks suuremat hulka koodi ja seega kasvataks keerukust. Samuti, mida rohkem koodi, seda rohkem on koodis võimalikke vigu. Vajadus lahendada sama ülesannet erinevates rakendustes kasvatab koodi hulka ning süsteemi keerukust veelgi. ## Küsimus: Millised on võimalikud lähenemised andmebaasirakenduste loomisele? **Vastus:** Lähtumine objektidest. Andmebaasirakendus on realiseeritud mõnes objektorienteeritud programmeerimiskeeles. Sõnasta funktsionaalsed nõuded (kasutuslugude või kasutusjuhtudena). Koosta rikkalik valdkonnamudel, millest tekivad lõpuks objektorienteeritud programmi klassid (domain driven design). Andmebaas on abiteenus andmete hoidmiseks, töö andmetega (äriloogika) käib rakenduses. Andmebaasirakendus on ülesannete ning koodi hulga mõttes "paks" ja andmebaas "õhuke". Võimalik, et andmebaasi struktuur kirjeldatakse rakenduse loomise vahendis ja lastakse vahendil enesel andmebaasiobjektid luua. Andmebaas ja rakendus suhtlevad mõnda objekt-relatsioonvastenduse (ORM) vahendit kasutades (nagu näiteks Entity Framework või Django ORM). Eesmärgiks on andmebaas ja selle keerukus rakenduse arendaja jaoks "ära peita". ORM vahend genereerib ise SQL lauseid, mille tulemuseks on sageli aeglasemalt täidetavad ja SQL-i kõiki võimalusi vähem kasutavad SQL laused kui võiksid olla ise kirjutatud laused. Andmestruktuurid (nt tabelid) tekivad klasside põhjal. Sellises andmebaasis on sageli liigset ja kontrollimatut andmete liiasust, sest tabelite ja klasside struktuuri leidmise parimad praktikad ei ole üks-ühele samad ning antud juhul lähtutakse tabelite leidmisel klassidest. Sellist lähenemist kutsutakse kood kõigepealt (code first) lähenemiseks. Info andmebaasi kohta on lisatud klassidele annotatsioonidena. Andmebaasi kirjeldus on salvestatud koodina. Süsteemi arendamine (sh andmebaasi arendamine) käib integreeritud programmeerimiskeskkonnas. Andmebaasis on vähe või pole üldse kitsendusi (sest see on ju äriloogika ja see on realiseeritud rakenduses ja seda ei peaks dubleerima). Üldiselt on pööratud vähem tähelepanu andmebaasi disaini halbade lõhnade vältimisele, kui rakenduse koodi halbade lõhnade vältimisele. Rakenduse lähtekood on kuningas ja andmebaas lihtsalt abivahend - auk - kuhu peaks saama andmeid kiiresti ära panna ja välja lugeda. Kahetsusväärselt näib  rakenduste ja andmebaaside vahel olevat sageli lai mõtteline lõhe ning liigagi sageli juhtub, et spetsialist, kes on kursis ühe poolega ei tunne hästi teist. Andmebaas võib olla rakenduse-spetsiifiline, st seda kasutabki ainult see üks rakendus. Kui puudub "suur pilt" e ettekujutus süsteemi üldisest arhitektuurist (mille loomist mõned tänapäeva moodsad paindmetoodikatest arendusmetoodikad vajalikuks ei pea), siis on kerge tekkima andmete liiasus erinevate selliste andmebaaside vahel. Kui põhikriteeriumid andmebaasi headuse hindamisel on andmete lugemise/kirjutamise kiirus ja selleks vajaliku koodi lihtsus ning andmebaasi kasutabki ainult üks rakendus (st teiste arendajatega ei pea tööd kooskõlastama), siis siit võib kergesti tekkida tahtmine eksperimenteerida mõne uue "skeemitut" andmebaasi ning (vähemalt reklaami järgi) kiiret lugemist/kirjutamist pakkuva NoSQL süsteemiga. Lähtumine andmetest. Andmebaasirakendus võib olla genereeritud andmebaasi põhjal. Kasutada võib Oracle APEX või pgApex sarnaseid vahendeid, mis pakuvad palju viisareid, visuaalseid komponente ning rakenduse loomist vähese programmeerimise vajadusega/programmeerimise vajaduseta. Veel näiteid arenduskeskkondadest, mis genereerivad andmebaasi põhjal koodi - PostGraphile ja Hasura. Leia põhilised andmeobjektid (põhiobjektid) ja nende elutsüklid. Koosta rikkalik kontseptuaalne andmemudel, millest lõpuks tekib andmestruktuuride (nt tabelite) kirjeldus. Funktsionaalsete nõuete kirjelduse saab tuletada elutsüklite kirjeldustest ja kontseptuaalsest andmemudelist. Süsteemi südamiku moodustavad andmed (andmebaas). Rakendused on nagu inimese riided, mida sageli (vastavalt moevoolude muutumisele) muudetakse. Andmebaasisüsteem on nagu virtuaalne operatsioonisüsteem. Andmebaasirakendus on ülesannete ning koodi hulga mõttes "õhuke" ja andmebaas "paks". Andmebaasis on jõustatud palju kitsendusi. Andmebaasi disaini halbu lõhnu üritatakse vältida nii palju kui võimalik, sest eksimused siin mõjutavad negatiivselt ka teisi süsteemi osi. Andmebaasis ei ole kontrollimatut andemete liiasust (vt andmestruktuuride täiendav normaliseerimine ja ortogonaalse disaini printsiibi rakendamine). Andmebaasis on avalik andmete liides, mis moodustub SQL-andmebaasi puhul tuletatud tabelitest ja rutiinidest ning mille kaudu serveeritakse kasutajatele just neid andmeid, mida neil on vaja ning just sellises vormis ja ulatuses nagu neile on vaja. Näiteks SQL:2016 lisandus JSON tugi ning paljude andmebaasisüsteemide tegijad on teinud tublisti tööd, et seda oma süsteemidesse lisada. Nii on näiteks võimalik kasutajatele (rakendustele) esitada andmeid läbi vaadete, kuhu andmed võetakse "tavalistest" tabelitest kuid need esitatakse JSON dokumentidena. Näiteks Oracle 23c lisandus võimalus luua spetsiaalse lausega (CREATE OR REPLACE JSON DUALITY VIEW) JSON formaadis andmeid esitavaid vaateid, kust kasutajad saavad nii andmeid lugeda kui muuta - andmed võetakse "tavalistest" tabelitest ja kirjutatakse "tavalistesse" tabelitesse Kuna rakendused saavad andmeid lugeda endale meeldival kujul, siis võiks see kaotada vajaduse kasutada ORM vahendeid. Enamasti kasutavad sama andemabaasi erinevad andmebaasirakendused. Andmebaas on nende jaoks ühise tõe allikas. Loomulikud on võimalikud ka pooltoonid selliste lähenemiste vahel, mis üritavad kombineerida parimat mõlemast. Lähtumine objektidest on kindlasti väga populaarne ja ilmselt tänapäeval valdav. Aga see ei tähenda, et lähtumine andmetest poleks võimalik ja teatud olukordades igati sobiv.Täpsemalt on see minu hinnangul sobiv olukorraks kus andmebaasirakenduse näol on tegemist CRUD rakendusega (andmete lugemise ja haldamise rakendusega), mis muuhulgas võimaldavad olemeid erinevate seisundite vahel liigutada.Sellise süsteem äriloogika moodustub: reeglitest andmetele SQL-andmebaasides saab kontrolli realiseerida deklaratiivsete kitsenduste ja trigeritega reeglitest andmete muutumisele (nt millised seisundimuudatused on lubatud) SQL-andmebaasides saab kontrolli realiseerida trigeritega reeglitest sellele, kuidas kasutajale andmeid esitades tuleb need teatud viisil kokku panna SQL-andmebaasides saab realiseerida vaadetena/hetktõmmistena/tabelifunktsioonidena kogu moodsa SQLi andmekäitluskeele võimsust ära kasutades andmemuudatuste tegemisest SQL-andmebaasides saab realiseerida andmebaasiserverites talletatud rutiinides Kõige selle jaoks on väga hea koht andmebaas. Andmekeskset lähenemist propageerib näiteks Helsingi Deklaratsioon (IT-versioon). Sellise andmebaasi näol on tegemist paksu e jämeda e nutika andmebaasiga. **Märksõnad:** paks andmebaas, jäme andmebaas, nutikas andmebaas, arukas andmebaas, kõhn andmebaas, peenike andmebaas, juhm andmebaas, thick database, thickDB, smart database, smartDB, thin database, dumb database ## Küsimus: Millist räsifunktsiooni tuleks kasutada andmebaasis hoitavate paroolide räsimiseks (avateksti peitmiseks)? **Vastus:** Kõigepealt mõned eestikeelsed allikaviiited. Cybernetica AS, 2013. Krüptograafiliste algoritmide kasutusvaldkondade ja elutsükli uuring. Aruanne. Versioon 3.1. 31. detsember 2013. a. [WWW] https://www.id.ee/wp-content/uploads/2020/01/kruptograafiliste_algoritmide_elutsukli_uuring_II.pdf Cybernetica AS, 2018. Krüptograafiliste algoritmide elutsükkel. Uuring. Versioon 2.0. 9. veebruar 2018. a. [WWW] https://www.id.ee/wp-content/uploads/2022/11/kruptograafiliste-algoritmide-elutsukkel-2017.pdf Cybernetica AS, 2023. Krüptoalgoritmid ning nende tugi teekides ja infosüsteemides. Tehniline dokument ver 2.0  15. juuni 2023. a. [WWW] https://www.id.ee/wp-content/uploads/2023/06/cryptoreport-2023-final.pdf Cybernetica (2023) kirjutab, et viimasel viiel aastal on sadu näiteid rünnakutest, mis järgivad järgnevat mustrit. "Infosüsteemis kaitstakse lõppkasutajate paroole liiga nõrgalt (paroole hoitakse kas avatekstina või räsituna mõne lihtsa meetodiga – tavapärane on standardse räsifunktsiooni ühekordne rakendamine). Sissetungija varastab kasutajate andmebaasi, mis sisaldab kasutajatunnuseid (tüüpiliselt e-posti aadress) ning paroole või parooliräsisid ning nõrkade parooliräside korral arvutab neist jõuründega paroolide väärtused. Murdunud paroolide abil saab teenuses kasutajakontosid üle võtta ning kuivõrd inimesed kasutavad sama parooli väga tihti paljudes teenustes, saab neid paroole pruukida kasutaja kontode ülevõtmiseks teisteski teenustes." Seega ei tuleks andmebaasis hoida mitte paroolide avateksti, vaid tuleb hoida paroolide soolatud räsi, kusjuures algse parooli jõuründega leidmine peaks olema võimalikult ressursimahukas. Räsi leitakse räsifunktsiooniga. Cybernetica (2023) defineerib räsifunktsiooni kui funktsiooni, mis võtab oma sisendiks vaid sõnumi ning väljastab (tavaliselt fikseeritud pikkusega) sõnumilühendi ehk räsi.Cybernetica (2013) jaotises 2.3 kirjutatakse erinevate räsifunktsioonide turvalisusest. 2013. aasta detsembri lõpu seisuga kirjutab dokument muuhulgas räsifunktsioonide kohta: "5 aasta jooksul turvalised primitiivid: Blowfish, AES (kõik standardsed võtmepikkused), RSA-2048 (ja diskreetse logaritmi põhised süsteemid mooduli pikkusega 2048 bitti), SHA-2, SHA-3, RIPEMD-160" 2018. aastal ilmus krüptograafiliste algoritmide elutsükli uuringu uus versioon (Cybernetica, 2018), mis sisuliselt kordas sama soovitust. Selles kirjutatakse: "2017. aasta veebruaris leidis Google’i poolt toetatud teadlaste meeskond lõpuks ammuoodatud kollisiooni räsifunktsioonile SHA-1. Kuigi kollisiooni olemasolu ei tähenda automaatselt kõigi kasutusstsenaariumite ebaturvaliseks muutumist, kordame siinkohal jubakõigis eelmistes krüptograafiliste algoritmide elutsükli uuringutes antud soovitust SHA-1 käibelt kõrvaldada. Asenduseks sobivad kõik SHA-2 ja SHA-3 perekonna räsifunktsioonid. ... Nagu ülal juba mainitud, pole viimase aasta jooksul peale SHA-1 kollisiooni leidmise märkimisväärseid krüptograafilisi läbimurdeid toimunud. Seega kehtivad üldjoontes eelmistes aruande versioonides antud soovitused."2023. aasta aruandes soovitab Cybernetica paroolide räsimiseks samuti SHA-2 ja SHA-3 perekondade algoritme, aga ka PBKDF2, scrypt ja Argon2. Näiteprojektis kasutatava populaarse ja suure realisatsioonide arvuga bcrypt algoritmi kohta toovad nad negatiivse poole pealt välja piirangud parooli pikkusele (72 baiti), suhtelise nõrkuse spetsiifilist riistvara kasutavate jõurünnete suhtes, bcrypt ei kuulu ühegi riikliku agentuuri poolt soovitatud algoritmide nimekirja. Nad kirjutavad "FPGA-põhiste rünnete vastase nõrkuse tõttu peab uutes süsteemides kasutama spetsiifilisi vastumeetmeid rakendavaid algoritme, nagu näiteks scrypt."Aineprojektis loetakse ebasobivateks algoritmideks MD5 ja SHA-1, kuid mitte bcrypt. **Märksõnad:** räsifunktsioon, räsi, parool, salasõna, pgcrypto ## Küsimus: Mis vahe on välisvõtme spetsifikatsioonis ON UPDATE/ON DELETE RESTRICT ja ON UPDATE/ON DELETE NO ACTION vahel? **Vastus:** ON DELETE/ON UPDATE RESTRICT tähendab, et viidete terviklikkust kontrollitakse, enne andmemuudatuse tegemist. Kui muudatuse tulemus rikuks viidete terviklikkuse reeglit, siis seda muudatust ei hakata tegema.   ON DELETE/ONUPDATE NO ACTION tähendab, et andmemuudatus tehakse ära ja kui tulemuseks on viidete terviklikkuse viga, siis rullitakse muudatus tagasi.   RESTRICT on vea tekkimist ennetav tegevus, NO ACTION on tegevusetus, millele järgneb andmebaasisüsteemi poolt vea tekkimisele reageerimine. Seda kirjeldab SQL standard (2011. aasta redaktsioon), kus on RESTRICT ja NO ACTION kohta kirjas järgnev.   Even if constraint checking is not deferred, ON UPDATE/ON DELETE RESTRICT is a stricter condition than ON UPDATE/ON DELETE NO ACTION. ON UPDATE/ON DELETE RESTRICT prohibits an update/a delete to a particular row if there are any matching rows; ON UPDATE/ON DELETE NO ACTION does not perform its constraint check until the entire set of rows to be updated/deleted has been processed.   SQL lubab lükata kitsenduste täidetuse kontrolli transaktsiooni e tehingu lõppu (deferred constraint checking). See tähendab, et transaktsiooni käigus võivad tehtud muudatused minna selle kitsendusega vastuollu, kuid kui transaktsiooni lõpuks on andmed kitsendusega kooskõlas, siis võtab andmebaasisüsteem transaktsiooni käigus tehtud andmemuudatused vastu. Välisvõtme kitsenduse puhul ei saa kompenseeriva tegevuse läbiviimist transaktsiooni lõppu lükata. Teiste sõnadega, kui kasutada ON UPDATE/ON DELETE RESTRICT, siis kontrollitakse ikkagi koheselt seda, kas viidete terviklikkuse reegel oleks muudatuse tulemusel täidetud või mitte ja kui ei ole, siis lükatakse muudatus tagasi. PostgreSQLis ebaõnnestub sellisel juhul kogu transaktsioon, mis seda muudatust sisaldab.   SQL standard (2011. aasta versioon) kirjutab järtgnevat: "Referential actions are carried out before, and are not part of, the checking of a referential constraint. Deferring a referential constraint defers the checking of the <search condition> of the constraint (a <match predicate>) but does not defer the referential actions of the referential constraint."   PostgreSQL dokumentatsioon ütleb: "NO ACTION means that if any referencing rows still exist when the constraint is checked, an error is raised; this is the default behavior if you do not specify anything. (The essential difference between these two choices is that NO ACTION allows the check to be deferred until later in the transaction, whereas RESTRICT does not.)" Näide PostgreSQLis.   CREATE TABLE Vanem (vanem_id INTEGER, CONSTRAINT pk_vanem PRIMARY KEY (vanem_id));   INSERT INTO Vanem(vanem_id) VALUES (1);   CREATE TABLE Laps (laps_id INTEGER, vanem_id INTEGER NOT NULL, CONSTRAINT pk_laps PRIMARY KEY (laps_id), CONSTRAINT fk_laps_vanem FOREIGN KEY (vanem_id) REFERENCES Vanem(vanem_id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED);   INSERT INTO Laps (laps_id, vanem_id) VALUES (1,1); START TRANSACTION; DELETE FROM Vanem; /*ERROR:  update or delete on table "vanem" violates foreign key constraint "fk_laps_vanem" on table "laps"DETAIL:  Key (vanem_id)=(1) is still referenced from table "laps".*/ ROLLBACK; /*Transaktsioon ebaõnnestus*/   DROP TABLE Laps;   CREATE TABLE Laps (laps_id INTEGER, vanem_id INTEGER NOT NULL, CONSTRAINT pk_laps PRIMARY KEY (laps_id), CONSTRAINT fk_laps_vanem FOREIGN KEY (vanem_id) REFERENCES Vanem(vanem_id) ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED);   INSERT INTO Laps (laps_id, vanem_id) VALUES (1,1);   START TRANSACTION; DELETE FROM Vanem; DELETE FROM Laps; COMMIT; /*Transaktsioon õnnestus, sest transaktsiooni lõpuks oli eemaldatud ka kustutatud vanemtabeli reaga seotu lapstabeli rida.*/Kui Te ei kasuta viidete terviklikkuse reegli täidetuse kontrollimise transaktsiooni lõppu lükkamise võimalust, siis on RESTRICT/NO ACTION lõpptulemus sama - viidete terviklikkust rikkuvaid andmemuudatusi teha ei saa. Soovitan sellisel juhul läbivalt kasutada kas ühte või teist, kuid mitte neid läbisegi, sest see võib tekitada asjatut segadust selles mõttes, et kas andmebaasi tegija on tahtnud konkreetse kitsenduse juures just NO ACTION või RESTRICT kasutamisega midagi öelda (ilmselt ei ole).Kui Te kompenseerivat tegevust ei määra, siis vaikimisi käitumine on NO ACTION. Siin on veel üks näide NO ACTION ja RESTRICT erinevuste kohta, mis tuleb välja käitumises seoses tabelitega, mis on üksteisega välisvõtmete kaudu kokku "aheldatud". RESTRICT korral kustutamine ebaõnnestub, sest viidete terviklikkust kontrollitakse enne vanemtabelist rea kustutamist ja selleks ajaks pole teise välisvõtmete ahela kaudu kustutamine lapstabelisse kohale jõudnud. Vastusele lisatud failis on selle näite SQL kood ja seda saab katsetada kasvõi näiteks DB Fiddle keskkonnas.NB! Oracles ei saa välisvõtme deklareerimisel RESTRICT määrata. Välisvõtme kitsenduse definitsioonis ei saa ka kirjutada NO ACTION - kuid kui jätate kompenseeriva tegevuse täpsustamata, siis NO ACTION on vaikimisi määrang.Näide Oracles, kus järgmise lausega loodud tabelis oleval välisvõtme kitsendusel on ON UPDATE NO ACTION ja ON DELETE NO ACTION omadus.CREATE TABLE Laps (laps_id NUMBER(10),vanem_id NUMBER(10) NOT NULL,CONSTRAINT pk_laps PRIMARY KEY (laps_id),CONSTRAINT fk_laps_vanem FOREIGN KEY (vanem_id) REFERENCES Vanem(vanem_id)); **Märksõnad:** viidete terviklikkus, kompenseeriv tegevus, välisvõti, võõrvõti, PostgreSQL, Oracle ## Küsimus: Mis võib mõjutada andmebaasis toimuvate lugemis ja muutmisoperatsioonide töökiirust? Millele võiks töökiiruse parandamisel tähelepanu pöörata? **Vastus:** Nimetan järgnevalt mõningaid aspekte koos viidetega lõputöödele, mis seda aspekti käsitlevad. Indekseid ei ole piisavalt, indekseid on liiga palju, indeksid on üleliigsed. Isikute otsimine nime alusel PostgreSQL andmebaasis ettevõtte X näitel Materjaliseeritud vaadete e hetktõmmiste kasutamine. Need võimaldavad päringutulemusi ette välja arvutada, kuid samas kulub nende ettearvutatud andmete hoidmiseks ja värskendamiseks ressursse. Andmebaasi struktuur pole ülesande jaoks sobivaim. Graafide esitamine SQL-andmebaasides Jõudluse analüüs ning veebirakenduse loomise keerukus Couchbase ja JSONB tüübiga PostgreSQL põhjal Denormaliseerimise praktika uurimine ühe SQL-andmebaasi näitel Mitme väite ühe andmeväärtusena esitamise eelised ja puudused SQL-andmebaasides MongoDB ja JSON tüüpe kasutava PostgreSQLi jõudluse võrdlemine Hierarhiliste andmete esitamine SQL-andmebaasides kolme disainilahenduse näitel Andmebaasikeele lause on konkreetse andmebaasisüsteemi jaoks ebasobiva süntaksiga, mis tingib halva täitmisplaani valiku. Mõnede SQL-andmebaasisüsteemide võimekusest SQLi keelelise liiasuse silumisel Andmebaasikeele lause on lihtsustamata. Näiteks ühendatakse lauses mittevajalikke tabeleid või on tingimused sellised, mida saaks lihtsustada. Päringu filtri predikaadi automaatne lihtsustamine kahe SQL-andmebaasisüsteemi näitel Mõnede ebaotstarbekate SQL päringute optimeerimine Oracle ja PostgreSQL andmebaasisüsteemides Andmebaasisüsteemi juhtparameetrite väärtused. Andmebaasi optimeerimine ning selles toimuvate operatsioonide jõudluse analüüs ühe Oracle andmebaasi näitel Andmete salvestusviis kettal. Reapõhise ja veerupõhise andmete salvestamise võrdlus kahe SQL-andmebaasisüsteemi näitel ## Küsimus: Tabelis on veerg e_meil unikaalsuse kitsendusega ja sellele viitavad välisvõtme kitsendused. Soovin veerul e_meil jõustada tõstutundetu unikaalsuse kontrolli. Kuidas seda teha? **Vastus:** Järgnevad koodinäited on tehtud PostgreSQL jaoks. Oracle andmebaasi kasutamise korral tekiks samasugune probleem ja ka lahendusvariandid oleksid samasugused.Olgu andmebaasis tabelid: [Meiliaadress]-1-----0..1-[Kasutajakonto]CREATE TABLE Meiliaadress (e_meil VARCHAR(254) NOT NULL,CONSTRAINT pk_meiliaadress PRIMARY KEY (e_meil),CONSTRAINT chk_meiliaadress_e_meil CHECK (e_meil LIKE '%@%'));CREATE TABLE Kasutajakonto (e_meil VARCHAR(254) NOT NULL,on_aktiivne BOOLEAN NOT NULL DEFAULT TRUE,CONSTRAINT pk_kasutajakonto PRIMARY KEY (e_meil),CONSTRAINT fk_kasutajakonto_meiliaadress FOREIGN KEY (e_meil) REFERENCES Meiliaadress (e_meil) ON UPDATE CASCADE ON DELETE CASCADE);INSERT INTO Meiliaadress(e_meil) VALUES ('mart.mets@hot.ee');INSERT INTO Kasutajakonto(e_meil) VALUES ('mart.mets@hot.ee');Soovin tabelis Meiliaadress veerul e_meil kontrollida unikaalsust tõstutundetult (st kui on näiteks registreeritud meiliaadress mart.mets@hot.ee, siis ei saa registreerida meiliaadressi Mart.Mets@hot.ee). Selleks pean kustutama veerule e_meil viitama välisvõtme kitsenduse ja siis primaarvõtme kitsenduse.ALTER TABLE Kasutajakonto DROP CONSTRAINT fk_kasutajakonto_meiliaadress;ALTER TABLE Meiliaadress DROP CONSTRAINT pk_meiliaadress;Proovin jõustada tõstutundetut unikaalsust kasutades unikaalset funktsioonil põhinevat indeksit. See ebaõnnestub, sest välisvõtme kitsendust ei saa tagasi panna.CREATE UNIQUE INDEX pk_meiliaadress ON Meiliaadress(Upper(e_meil));ALTER TABLE Kasutajakonto ADD CONSTRAINT fk_kasutajakonto_meiliaadress FOREIGN KEY (e_meil) REFERENCES Meiliaadress (e_meil) ON UPDATE CASCADE ON DELETE CASCADE;ERROR:  there is no unique constraint matching given keys for referenced table "meiliaadress"Proovin jõustada tõstutundetut unikaalsust kasutades EXCLUDE kitsendust (UNIQUE kitsenduse üldistus, mis on spetsiifiline PostgreSQLile). See ebaõnnestub, sest välisvõtme kitsendust ei saa tagasi panna.DROP INDEX pk_meiliaadress;ALTER TABLE Meiliaadress ADD CONSTRAINTpk_meiliaadress EXCLUDE(Upper(e_meil) WITH =);ALTER TABLE Kasutajakonto ADD CONSTRAINT fk_kasutajakonto_meiliaadress FOREIGN KEY (e_meil) REFERENCES Meiliaadress (e_meil) ON UPDATE CASCADE ON DELETE CASCADE;ERROR:  there is no unique constraint matching given keys for referenced table "meiliaadress"Mida teha?Variant 1: Jõustada välisvõtme kitsenduste poolt tagatav viidete terviklikkus kasutades trigereid. Miks ma seda ei soovita? Idee on selles, et teha viidete terviklikkuse kontrolli trigeritega. Kui kustutan rea või muudan rida tabelis Meiliaadress, siis kontrollitakse, kas vastav rida on tabelis Kasutajakonto ja vastavalt siis muudetakse või kustutatakse see rida. See triger oleks seotud tabeliga Meiliaadress. Kui lisatakse rida tabelisse Kasutajakonto või muudetakse tabelis Kasutajakonto meiliaadressi, siis kontrollitakse, kas vastav meiliaadress on tabelis Meiliaadress. See triger oleks seotud tabeliga Kasutajakonto. Keerukust lisab see, et PostgreSQLis ei blokeeri andmete lugemine nende andmete samaaegset muutmist (tänu multiversioon konkurentsjuhtimisele) ja seega tuleb trigerites kasutada SELECT .. FOR UPDATE või luua kitsenduste trigerid, mille kontroll on transaktsiooni lõpus.Andmebaasisüsteemi poolt läbiviidav tabeli elimineerimise teisendus eeldab deklaratiivsete (st mitte trigerite abil realiseeritud) välisvõtme kitsenduste olemasolu.Variant 2: Lisada tabelisse Meiliaadress surrogaatvõtme veerg meiliaadress_id, kus on süsteemi genereeritud unikaalsed täisarvud. Kasutada tabelis Kasutajakonto välisvõtmena meiliaadress_id, mitte e_meil.Variant 3:Taastan algse olukorra.ALTER TABLE Meiliaadress DROP CONSTRAINT pk_meiliaadress;ALTER TABLE Meiliaadress ADD CONSTRAINT pk_meiliaadress PRIMARY KEY (e_meil);ALTER TABLE Kasutajakonto ADD CONSTRAINT fk_kasutajakonto_meiliaadress FOREIGN KEY (e_meil) REFERENCES Meiliaadress (e_meil) ON UPDATE CASCADE ON DELETE CASCADE;Võtan kasutusele kasutajanime veeru (täiendada tuleks ka andmebaasi disaini mudeleid).ALTER TABLE Meiliaadress ADD COLUMN kasutajanimi VARCHAR(254);Kasutajanimi on meiliaadress.UPDATE Meiliaadress SET kasutajanimi=e_meil;Kasutajanimi on kohustuslik.ALTER TABLE Meiliaadress ALTER COLUMN kasutajanimi SET NOT NULL;Kasutajanimi on tõstutundetult unikaalne.ALTER TABLE Meiliaadress ADD CONSTRAINTak_meiliaadress_kasutajanimi EXCLUDE(Upper(kasutajanimi) WITH =);Kasutajanimi on meiliaadress.ALTER TABLE Meiliaadress ADD CONSTRAINT chk_meiliaadress_e_meil_kasutajanimi CHECK (Upper(e_meil)=Upper(kasutajanimi));Triger, mis reageerib andmete lisamisele ja uuendamisele tabelis Meiliaadress.CREATE OR REPLACE FUNCTION f_meiliaadress_kasutajanimi() RETURNS trigger AS $$BEGINNEW.kasutajanimi:=NEW.e_meil;RETURN NEW;END;$$ LANGUAGE plpgsql SECURITY DEFINERSET search_path = public, pg_temp;COMMENT ON FUNCTION f_meiliaadress_kasutajanimi() IS 'See trigeri funktsioon määrab enne uue reatabelisse lisamist kasutajanimeks meiliaadressi.Kasutaja peaks registreerima meiliaadressi, mitte kasutajanime.';CREATE OR REPLACE TRIGGER trig_meiliaadress_kasutajanimi BEFORE INSERT OR UPDATE OF e_meil, kasutajanimi ONMeiliaadressFOR EACH ROW EXECUTE FUNCTION f_meiliaadress_kasutajanimi();Katsetan, kas lahendus töötab nagu vaja.Sama meiliaadressi ei saa mitu korda kasutada.INSERT INTO Meiliaadress(e_meil) VALUES ('mart.mets@hot.ee');ERROR:  duplicate key value violates unique constraint "pk_meiliaadress"Sama meiliaadressi ei saa mitu korda kasutada isegi siis, kui kasutada teistsugust suur- ja väiketähtede kombinatsiooni.INSERT INTO Meiliaadress(e_meil) VALUES ('Mart.Mets@hot.ee');ERROR:  conflicting key value violates exclusion constraint "ak_meiliaadress_kasutajanimi"Sellist meiliaadressi ei olnud registreeritud.INSERT INTO Meiliaadress(e_meil) VALUES ('Martin.Mets@hot.ee');--OKKa olemasolev meiliaadressi või kasutajanime uuendamine ei anna tulemuseks reeglitele mittevastavaid andmeid.UPDATE Meiliaadress SET e_meil='Mart.Mets@hot.ee' WHERE e_meil='Martin.Mets@hot.ee';ERROR:  conflicting key value violates exclusion constraint "ak_meiliaadress_kasutajanimi"UPDATE Meiliaadress SET kasutajanimi='midagi' WHERE e_meil='Martin.Mets@hot.ee';--Tänu trigerile andmed ei muutunud. **Märksõnad:** tõstutundetu unikaalsus, PostgreSQL, funktsioonil põhinev indeks, EXCLUDE kitsendus, triger, välisvõtme kitsendus ## Küsimus: Ülesande 10 juhendis on öeldud, et f_is_user funktsiooni asendus tuleb teha kahes kohas. Esimene koht on .CommandText = "public.f_is_user" mille muutsin .CommandText = "public.f_on_juhataja"'ks, kuid ei leidnud teist kohta kus seda muuta. **Vastus:** Private Sub OK_Click() ... Do While Not rst.EOF result = rst!f_is_user ... See on sündmusprotseduuris, mis käivitub OK nupule vajutamisel. Kõige lihtsam on vajutada Ctrl+F ja otsida f_is_user. **Märksõnad:** vba, MS Access, sündmusprotseduur, funktsioon, kasutaja tuvastamine, f_is_user ## Küsimus: Ülesandes 10 kirjeldatud kasutaja tuvastamise funktsioon ei toimi. Kutsume selle välja, andes ette kasutajanime ja parooli, kuid tulemus on FALSE (kuid peaks olema TRUE). Mis võib olla viga? **Vastus:** Võimalikke põhjuseid, miks selline funktsioon ei tööta. 1. Kasutajanimi on vale. 2. Parool on vale. 3. Parooli räsimise UPDATE lauset käivitati rohkem kui üks kord. Selle tulemusena leiti ja salvestati olemasoleva parooli räsi põhjal uus räsiväärtus. 4. Katsetatav isik pole töötaja, pole juhataha või pole isiku või töötajana sobivas seisundis. Midagi nendest põhjustab vea. Variandi 3 lahendamiseks aitab see, kui kirjutate isikutele avatekstilised paroolid ja käivitate seejärel uuesti räsiväärtuse leidmise UPDATE lause - üks kord! Võite katsetamise huvides määrata kõikidele isikutele ühesuguse vabatekstilise parooli. Näiteks: UPDATE Isik SET parool='seepoleTurvaline'; **Märksõnad:** Ülesanne 10, kasutaja tuvastamine, turvalisus --- # Teema: Andmebaasisüsteemid (Üldine) ## Küsimus: Juhul kui välisühendamist ei ole lause õige tulemuse saavutamiseks vaja, siis kas OUTER JOIN operatsiooni kasutamine INNER JOIN asemel mõjutab lause täitmisplaani valikut ja seega ka lause täitmise kiirust? **Vastus:** Sõltub päringust ja andmebaasisüsteemist.Katsetasin Oracles (12.1) ja PostgreSQL (14) põhjal, mis olid samas serverarvutis. Katsetamisel kasutatud andmebaas ja andmed olid ühesugused.Oletame, et andmebaasis on järgnevale kontseptuaalsele strukuurile vastavad tabelid:[Vanem]-1--------0..*-[Laps]Päringud:SELECT *FROM Laps INNER JOIN Vanem USING (vanem_id);SELECT *FROM Laps LEFT JOIN Vanem USING (vanem_id);on sellisel juhul loogiliselt samaväärsed, st annavad alati sama tulemuse. INNER JOIN operatsioon oleks antud juhul piisav, sest iga laps on seotud täpselt ühe vanemaga. Kas LEFT JOIN kasutamine mõjutab antud juhul töökiirust?Lühike vastus on, et PostgreSQL ja Oracle puhul ei tundu sisulist mõju olevat. SIIN on katsetus PostgreSQL ja Oracle baasil, millele see väide tugineb. Huviline saab katsetust ise läbi viia ja täiendavaid päringuid koostada.PostgreSQLi puhul tuli siiski välja üks puudus - ühe katsetatud päringu korral oskas PostgreSQL tabeli elimineerimise teisendust teha siis, kui kasutati LEFT JOIN'i, kuid mitte siis kui kasutati INNER JOIN'i.Soovitan selles olukorras siiski kasutada INNER JOIN operatsiooni. Kood on lugejale lihtsamini mõistetav. Kontseptuaalselt küsib LEFT JOIN rohkem andmeid kui INNER JOIN. Kui selliseid andmeid pole vaja või ei saa esineda, siis ei maksa neid küsidagi. Koodi ülekanne teistesse süsteemidesse tekitab vähem probleeme. Mitte kõik andmebaasisüsteemid ei pruugi osata aru saada sellest, et kuigi need laused näevad erinevad välja, annavad need alati sama tulemuse ja seega võiks neil olla sama täitmise protseduur (lugege näiteks seda arutelu). **Märksõnad:** tabeli elimineerimise teisendus, PostgreSQL, Oracle, töökiirus, jõudlus, välisühendamine, ühendamisoperatsioon, päringutöötlus, täitmisplaan ## Küsimus: Juhul kui välisühendamist ei ole lause õige tulemuse saavutamiseks vaja, siis kas OUTER JOIN operatsiooni kasutamine INNER JOIN asemel mõjutab lause täitmisplaani valikut ja seega ka lause täitmise kiirust? (2) **Vastus:** Sõltub päringust ja andmebaasisüsteemist.Katsetasin Oracles (12.1) ja PostgreSQL (14) põhjal, mis olid samas serverarvutis. Katsetamisel kasutatud andmebaas ja andmed olid ühesugused.Vähemalt konkreetsete süsteemide ja katsetatud lausete puhul tingis just OUTER JOIN (välisühendamise) kasutamine tabeli elimineerimise teisenduse rakendamise andmebaasisüsteemi poolt (juhul kui see oli võimalik), mis andis tulemuseks parema töökiiruse. Tabeli elimineerimise teisenduse idee seisneb selles, et kui päringus viidata tabelile, mida pole lause täitmiseks vaja lugeda, siis kirjutab andmebaasisüsteem ise lause ümber nii, et seda tabelit ei kasutata. Katsetes kasutatud laused olid loogiliselt samaväärsed, st INNER vs OUTER JOIN kasutamine ei muutnud tulemust.Andmebaas:[Party]-1----------0..1-[Person]-1--------0..*-[Health_care_visit]Tabelis Party - 100 000 ridaTabelis Person - 70 000 ridaTabelis Health_care_visit - 1 miljon ridaKatse 1Lause 1:SELECT Count(*) AS cntFROM Health_care_visit LEFT JOIN Person ON Health_care_visit.patient_id=Person.party_idLEFT JOIN Party USING (party_id);Lause 2:SELECT Count(*) AS cntFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idINNER JOIN Party USING (party_id);PostgreSQL tulemus: (LEFT JOIN parem)Täitmisplaanid erinevad.Lause 1 täitmine 0.21 sekundit (tänu tabeli elimineerimise teisendusele loeti ainult tabelit Health_care_visit).Lause 2 täitmine 0.76 sekundit (loeti tabelit Health_care_visit ja lisaks tabelite Person ja Party primaarvõtme indeksit).Oracle tulemus: (LEFT JOIN parem)Täitmisplaanid erinevad.Lause 1 täitmine 0.07 sekundit (tänu tabeli elimineerimise teisendusele loeti ainult tabeli Health_care_visit primaarvõtme indeksit).Lause 2 täitmine 0.34 sekundit (loeti tabelit Health_care_visit indeksit ja lisaks tabeli Party primaarvõtme indeksit).Katse 2Lause 1SELECT Count(*) AS cntFROM Health_care_visit LEFT JOIN Person ON Health_care_visit.patient_id=Person.party_idLEFT JOIN Party USING (party_id)WHERE Health_care_visit.visit_fee>100;Lause 2:SELECT Count(*) AS cntFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idINNER JOIN Party USING (party_id)WHERE Health_care_visit.visit_fee>100;PostgreSQL tulemus: (LEFT JOIN parem)Täitmisplaanid erinevad.Lause 1 täitmine 0.3 sekundit (tänu tabeli elimineerimise teisendusele loeti ainult tabelit Health_care_visit).Lause 2 täitmine 0.85 sekundit (loeti tabelit Health_care_visit ja lisaks tabelite Person ja Party primaarvõtme indeksit).Oracle tulemus: (LEFT JOIN parem)Täitmisplaanid erinevad.Lause 1 täitmine 0.11 sekundit (tänu tabeli elimineerimise teisendusele loeti ainult tabelit Health_care_visit).Lause 2 täitmine 0.75 sekundit (loeti tabelit Health_care_visit ja lisaks tabeli Party primaarvõtme indeksit).Katse 3:Lause 1:SELECT Health_care_visit.patient_id, Health_care_visit.from_date, Health_care_visit.thru_date, Person.last_name, Person.height, Person.weight, Party.contact_numberFROM Health_care_visit LEFT JOIN Person ON Health_care_visit.patient_id=Person.party_idLEFT JOIN Party USING (party_id);Lause 2:SELECT Health_care_visit.patient_id, Health_care_visit.from_date, Health_care_visit.thru_date, Person.last_name, Person.height, Person.weight, Party.contact_numberFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idINNER JOIN Party USING (party_id);PostgreSQL tulemus (viik):Täitmisplaanid veidi erinevad (tabelid ühendati samas järjekorras, kasutati hash joini).Lause 1 täitmine 0.74 sekundit (loeti kõiki tabeleid).Lause 2 täitmine 0.74 sekundit (loeti kõiki tabeleid).Oracle tulemus: (INNER JOIN veidi parem)Täitmisplaanid erinevad (tabelid ühendati erinevas järjekorras, kasutati hash joini).Lause 1 täitmine 6.76 sekundit (loeti kõiki tabeleid).Lause 2 täitmine 5.82 sekundit (loeti kõiki tabeleid).Tabeli elimineerimise teisendust ei saa kasutada, sest päringus küsitatakse andmeid kõigist tabelitest. **Märksõnad:** tabeli elimineerimise teisendus, PostgreSQL, Oracle, töökiirus, jõudlus, välisühendamine, ühendamisoperatsioon, päringutöötlus, täitmisplaan ## Küsimus: Kas ja miks peab rutiinis või trigeris kasutama SELECT ... FOR UPDATE? **Vastus:** Kas ... FOR UPDATE on vajalik sõltub kõigepealt kasutatavast andmebaasisüsteemist. PostgreSQLis ja Oracles on SELECT ... FOR UPDATE vaja kasutada siis, kui teete trigeri protseduuris või lihtsalt rutiinis mingi tingimuse kontrolliks päringu (SELECT lause) teise tabelisse või ka sama tabeli teiste ridade põhjal. Sellega tagate, et kui andmed, mille põhjal kontrolli teete, on parajasti muutmisel, siis jätkub Teie trigeri või rutiini töö alles siis, kui see muutmine on lõppenud ja on selge, millised on uued andmed. Lihtsalt SELECT seda ei taga, sest nii Oracle kui PostgreSQL kasutavad multiversioon-konkurentsjuhtimist (MVCC, multi-version concurrency control) ning andmete muutmine/kustutamine ei blokeeri nende samaaegset lugemist. SELECT ... FOR UPDATE üritab panna loetud ridadele eksklusiivse luku ja see ebaõnnestub, kui need read on juba eksklusiivselt lukustatud, st keegi parajasti muudab neid. **Märksõnad:** triger, rutiin, lukustamine ## Küsimus: Kas ja millal eelistada NoSQL andmebaasi SQL-andmebaasi loomisele? **Vastus:** Arvan, et käesolevaks ajaks on NoSQL jõudnud haibitsüklis ülisuurte ootuste tipust üle, pettumuste lohust läbi, võibolla isegi juba taasavastamise tõusule. Üha rohkem ilmub seisukohti ja tähelepanekuid, mis osundavad lähenemise või süsteemide üldistele puudujääkidele (näide1, näide2, näide 3) ja konkreetsete süsteemide probleemidele (näide4, näide5, näide6). Muidugi saab öelda, et ühes või teises NoSQL süsteemis selliseid probleeme ei ole ja olemasolevad süsteemid arenevad kiiresti ja lahendavad käigupealt esilekerkinud probleeme, kuid küsimus on, kuidas see toode kümnete teiste seast üles leida ja kas on kindel, et selle teinud idufirma pole viie aasta pärast hingusele läinud. NoSQL süsteemid peavad oma arengus jõudma produktiivsuse platoole ja tõsised tegijad välja settima. Näen tõsist probleemi selles, et NoSQL süsteeme üritatakse kasutada ka seal, kus see pole kindlasti mõistlik. Teha raamatupidamise tarkvara NoSQL süsteemi põhjal on sama lahe kui kratsida kukalt pannes käe jalge vahelt läbi. Alguses paistab huvitav ja ekstravagantne, sellest tehtud piltidega saab sotsiaalmeedias praalida - pärast on kael ja keha kanged ning selg paigast ära. Mulle meeldis ühes arutelus võrdlus andmete ja koduse tööriistakuuri vahel. Oletame, et Teil on kuuris palju tööriistu. Üks võimalus on võtta erinevat tüüpi tööriistade jaoks kasutusele erinevad kastid. Kahtlemata võtab kastide valimine, neile siltide kleepimine ning tööriista ära panemisel õige kasti otsimine aega. Andmebaaside maailmas vastab sellele skeemi defineerimine SQL/relatsioonilises andmebaasis. Selle tulemusena on vajaliku tööriista leidmine kiire. Kas tõesti oleks lahendus, kus kuuris on hulk kaste ja tööriist pannakse esimesse vabasse kasti, kokkuvõttes kiirem ja parem? Andmebaaside maailmas vastaks sellele skeemitu (täpsemalt ainult lugemise skeemiga) NoSQL andmebaasi kasutamine. Näen NoSQL süsteemide peamist kasutusvaldkonda suurandmete (big data) hoiustamisel - andmeid on hästi palju, neid tuleb nagu kosest juurde ja andmete struktuur ei ole ühe vitsaga löödud, vaid küllaltki muutlik. Kena oleks need kuskile kiiresti ja odavalt ära panna, lootuses, et ehk on hiljem aega, tahtmist ja raha, et neid lähemalt uurida. Tööriistade näitel oleks see umbes midagi sellist. Asjade hunnikusse paigutajal oli oma süsteem ja ta leiab vajaliku kiiresti üles. Teistel see nii kiiresti ei lähe. Teisalt, nagu tõestavad seriaalid nagu American Pickers, võib sellisest hunnikust igasugu väärt kraami leida. Samamoodi ei tasu ka andmeid lihtsalt ära visata. Graafipõhistel andmebaasisüsteemidel on kindlasti oma kindel koht igat sorti võrgustike (kes on kelle sõber, kust kuhu tee viib või kaabel jookseb jne) andmete käepäraseks muutmisel. Arvan, et mõistlikuks arengusuunaks on SQL ja NoSQL kokkusulamine, mille näiteks on PostgreSQLis JSON tüüpi andmetega töötamise võimalus. See võimaldab lahendusi, kus ühes geograafilises punktis oleva andmebaasi piires on teatud osa andmetest esitatud rohkem struktureeritult (eraldi veergudes) ja muutlikum osa andmeid on surutud kokku JSON andmeväärtustesse (vt kolmandat disaini selles näites). Kõiki neid andmeid kantseldab ACID omadusi toetav transaktsioonide juhtimise moodul. NoSQL and Technical Debt on ajaveebi postitus, mis selgitab, miks NoSQL süsteemide ilmumine pole muutnud väärtusetuks SQLi ning andmebaaside projekteerimise õppimist. Nende oskuste puudumine on arendajatel võlg, mis tuleb hiljem intressidega tagasi maksta. NoSQL oma "skeemitute" andmetega loob tegelikult tehnilist võlga. SQL ja NoSQL on nagu lennukid ja helikopterid. Mõlemad lendavad, kuid üks ei asenda teist. Kummalgi on omad kasutusvaldkonnad, kus nad on alternatiividest paremad ja edukamad. ## Küsimus: Kas päringute tegemine vaadete põhjal võib mõjutada päringute täitmise kiirust võrreldes päringute tegemisega otse baastabelite põhjal? **Vastus:** Jah. Vaadete kasutamine mõjutab täitmisplaanide valikut ja võib mõnikord viia ebaotstarbekate plaanide valimiseni. Kašnikova, D., 2015. Vaadete mõju päringute täitmisplaanide koostamisele kahe andmebaasisüsteemi näitel. Magistritöö. TTÜ Informaatikainstituut. [WWW] https://digi.lib.ttu.ee/i/?3676 (30.08.2016) Tsiteerin: Uuringu tulemused näitasid, et kuigi Oracle andmebaasisüsteemis põhjustab vaate põhjal päringu tegemine sageli teistsuguse täitmisplaani valimise kui otse baastabelite põhjal päringuid tehes, siis sellest tulenevad töökiiruse erinevused ei ole kuigi märgatavad. PostgreSQLis koostab andmebaasisüsteem (ilma turvabarjäärita) vaate põhjal tehtud päringule ning otse baastabelil tehtud päringule suurema tõenäosusega ühesuguse täitmisplaani. Kuid probleem on selles, et võrreldes Oraclega on see täitmisplaan mõnikord lihtsalt halb, olgu päring tehtud vaate põhjal või mitte. PostgreSQLis tuleks andmete turvalisuse tõstmiseks kasutada vaadetes turvabarjääre, kuid see võib tingida vaate põhjal tehtud päringule mitteoptimaalse (ja seega aeglaselt täidetava) täitmisplaani valimise. Siiski, mõeldes kõigile vaadete võimalikele eelistele ja puudustele leian, et vaated on hea ja kasulik vahend andmebaasi kapseldamiseks ning neid tuleks kasutada. ## Küsimus: Kuidas kasutatakse andmebaasisüsteeme suurtes, hajutatud süsteemides nagu näiteks Facebook või StackExchange? **Vastus:** Elu näitab, et loengutes ja praktikumides teevad paljud üliõpilased lisaks õppeserverile praktilisi katseid ja vaatluseid ka Facebookis :-) Kelle huvi pakub, siis sellele teatele lisatud faili jaotises 2.1 antakse ülevaade Facebooki andmebaasi arhitektuurist. Artikkel ise seostub teemadega 6 ja 12.Veel üks ühismeedia keskkond on StackExchange. Siin on pildiline ülevaade selle arhitektuurist. Nagu võite näha, siis sisemiselt kahte suurt andmebaasi, millest kummastki on tööversioon ja kuum varukoopia (hot standby), mis on tööversioonile võimalikult lähedane ja on mõeldud selleks, et tööversiooni tõrke korral kasutajate teenindamine üle võtta. ## Küsimus: Kuidas küsida päringuga andmebaasisüsteemi versiooni? **Vastus:** Seda võib näiteks olla vaja teha SQLi harjutamise liivakastides nagu DB Fiddle või SQL Fiddle.Microsoft SQL Server SELECT @@version;   Oracle Database SELECT * FROM V$VERSION; SQL Lite SELECT sqlite_version(); PostgreSQL SELECT version(); MySQL SELECT version();   MariaDB SELECT version();   ## Küsimus: Kuidas saab SQL-andmebaasides salvestada graafiandmeid ja nendega töötada? **Vastus:** Paljusid asju ja nähtuseid meie ümber võib ette kujutada graafina (näiteks sõprade ja tuttavate võrgustik - kes kellega suhtleb). Võimalusi, kuidas saaks SQL-andmebaasis salvestada graafide andmeid, et nende pealt oleks võimalikult lihtne otsingut teha, on otsitud juba kaua. SQL-andmebaasis graafiandmete põhjal päringute tegemist lihtsustas võimalus hakata tegema rekursiivseid päringuid.Selles magistritöös esitatakse kokku 16 erinevat SQL-andmebaasis graafiandmete esitamise disainilahendust, kusjuures vaatluse alt jäid välja disainid, kus graafi andmed oleks esitatud hierarhiliste JSON või XML dokumentidena. Töös eksperimenteeriti kahe andmebaasisüsteemiga (PostgreSQL 9.5 ja Oracle 12.1) ning kahe populaarse disainiga. Seega SQL-andmebaasisüsteemides on võimalused olemas, kuid need on siiski võibolla liiga kohmakad ja keerukad ning otsingud graafide põhjal pole piisavalt kiired, mis omakorda on inspireerinud selliste andmebaasisüsteemide turule tulekut, mille andmemudel (andmebaasi ehitusplokkide kirjeldus) põhinebki graafidel. Üks populaarsemaid selliseid andmebaasisüsteeme on Neo4j. Turule tuli mitmeid erinevaid graafipõhiseid andmebaasisüsteeme - igaühes oma andmebaasikeel. Kõik need süsteemid kuuluvad NoSQL vihmavarju alla - andmebaasi ehitusplokid on midagi muud kui "tabelid". Lõpuks saadi aru, et ühise standardiseeritud keele puudumine pärsib nende süsteemide arengut ja laiemat kasutuselevõttu ja nii käivitus püüdlus töötada välja esimene uus andmebaasikeele standard peale SQL-i - Graph Query Language (GQL) standard. See standard peaks valmima 2024. aasta kevadel.Ühe osana sellest püüdlusest lisandus SQL:2023 standardi versiooni uus osa - osa 16 - Property Graph Queries (SQL/PGQ). Selle kohaselt saab SQL-andmebaasis deklareerida omaduste graafi (lausega CREATE PROPERTY GRAPH), määrates ära, millistes andmebaasis olemasolevates tabelites on tippude (vertex) ja millistes tabelites on servade (edge) andmed. Seejärel saab omaduste graafi põhjal teha päringuid. Graaf on nagu vaade üle olemasolevate tabelite. Eesmärk on võimaldada SQL-andmebaasis graafipõhiseid päringuid lihtsamini teha. Graafi põhjal tehtavas päringu üks osa on MATCH klausel, kus on avaldis graafi mustrile vastavuse kontrolli alamkeeles (GPML). Selle avaldise abil saab kirjeldada graafis olevaid teid. GPML on ühine GQL ja SQL/PGQ jaoks. Seega SQL/PGQ toob osa GQL keele võimalustest otse SQLi. Teisalt pärib GQL mõned SQLi omadused.Graafi põhjal tehtava päringu tulemuseks on tabel, millega saab selles samas päringus teha neid samu operatsioone, mida kõigi teiste tabelitega – näiteks eemaldada korduseid, ridu sorteerida või ühendada teiste tabelitega. Kui soovida piirata graafi omaduste väärtuseid, siis tuleb deklareerida kitsendused graafi aluseks olevatele tabelitele. Graafi andmete muutmiseks tuleb muuta andmeid graafi aluseks olevates tabelites. Päringud täidetakse graafi aluseks olevate tabelite põhjal. Päringute kiirendamiseks tuleb luua indekseid graafi aluseks olevatele tabelitele. Oracle 23c, mis tuli välja samal aastal kui SQL:2023, pakub SQL/PGQ tuge. SIIN on näide Oracle andmebaasis omaduste graafi defineerimise ja selle põhjal päringute tegemise kohta. Iga soovija saaks seda Oracle tasuta pakutava Oracle Free andmebaasisüsteemiga ise järgi proovida. **Märksõnad:** property graph ## Küsimus: Kuidas valida üldiselt andmebaasirakenduse jaoks andmebaasisüsteemi? **Vastus:** Arutelu teemal, kuidas ettevõtted valivad enda infosüsteemide jaoks andmebaasisüsteeme ning milliseid meetodeid andmebaasisüsteemide arendajad kasutavad, et leida uusi kliente ja hoida kinni olemasolevaid. ## Küsimus: Mida tähendab WITH CHECK OPTION vaate definitsioonis? **Vastus:** See on vaatega seotud kitsendus, mida tuleks siduda sellise alampäringuga vaatega, mille korral lubab andmebaasisüsteem vaate kaudu andmeid muuta. Erinevates andmebaasisüsteemides on erinevad piirangud vaadetele, mille kaudu saab andmeid muuta. Kitsendus tagab, et INSERT ja UPDATE lausetes tehtud muudatused vaadetes põhjal peavad vastama vaate alampäringu tingimustele. Teiste sõnadega, õnnestunud INSERT lause vaatesse peab suurendama vaate kaudu nähtavate ridade arvu ja õnnestunud UPDATE lause vaate põhjal ei tohi vähendada vaate kaudu nähtavate ridade arvu. Veel teisiti öeldes tagab see, et vaade pole nagu must auk, kuhu lisatud rida ei ilmu vaatesse nähtavale ning vaade pole ka selline tabel, kust UPDATE lause tulemusel read ära kaovad - sellised käitumised oleksid kasutajale üllatavad ning arusaamatud. **Märksõnad:** vaade, tuletatud tabel, WITH CHECK OPTION ## Küsimus: Mille põhjal otsustada, kas kitsendus tuleks defineerida `DEFERRABLE` omadusega? Miks mitte määrata kõikide kitsenduste puhul `DEFERRABLE INITIALLY DEFERRED`? **Vastus:** DEFERRABLE INITIALLY DEFERRED kitsenduse definitsioonis tähendaks seda, et kitsenduse kontroll lükkub transaktsiooni lõppu - transaktsioon võib sisaldada mitut andmemuudatust, transaktsiooni käigus võivad muudatused olla kitsendusega vastuolus, kuid kui transaktsiooni lõpuks on andmed kitsendusega kooskõlas, siis andmebaasisüsteem ei tee sellest numbrit. Vaikimisi (NOT DEFERRABLE omadus) kontrollib PostgreSQL kitsenduse täidetust kas iga rea muutmise järel (NOT NULL, CHECK, PRIMARY KEY, UNIQUE kitsendused) või andmete muutmise lause täitmise järel (FOREIGN KEY, EXCLUDE kitsendused).Artiklis  Deferrable SQL Constraints in Depth tuuakse PostgreSQL näitel välja olukorrad, millal DEFFERRABLE kitsendusi kasutada ja millal mitte. DEFERRABLE kitsenduste kasutamise näidete hulgas on: andmete lisamine tabelitesse, mis kohustuslikke välisvõtmeid kasutades viitavad üksteisele (minu arvates peaks siinkohal üle vaatama andmebaasi struktuuri), eksklusiivsete ressursside ümberjagamine rühmade vahel (iga ressurss saab olla seotud vaid ühe rühmaga), unikaalsete järjekorranumbrite muutmine (parem lahendus võiks olla ujukomaarvude kasutamine järjekorranumbritena), andmete uude andmebaasi laadimise mugavamaks tegemine. DEFERRABLE kitsenduste probleemid on: selline kitsenduse omadus võib takistada andmebaasisüsteemil kasutada seda kitsendust päringu optimeerimisel  ja seega suurendada päringu täitmiseks kuluvat aega (siin on näide selle kohta Oracles), keerulisem silumine. Veel võib esile tõsta ülekantavuse. Näiteks saab kitsenduse täitmise kontrolli lükata transaktsiooni lõppu: Oracle 12c kõigi kitsenduse tüüpide puhul, PostgreSQL 14 ei saa CHECK ja NOT NULL kitsenduste puhul, MySQL 8 ei saa ühegi kitsenduse tüübi puhul. ## Küsimus: Millised on PostgreSQLi ja Oracle eelised võrreldes üksteisega? **Vastus:** Vastus peegeldab õppejõu isiklikku seisukohta, puudutab eeskätt andmebaaside programmeerimist ning välja toodud nimekirjad pole kaugeltki mitte ammendavad. Punktid ei ole tähtuse järjekorras - erinevatele inimestele ja erinevates olukordades on tähtsad erinevad asjad. PostgreSQL eeliseid võrreldes Oraclega. Avatud lähtekood, kusjuures litsents on väga liberaalne, st ei sea märkimisväärseid piiranguid. Litsentsitasuta. Lisaks lähtekoodi avalikkusele on ka andmebaasisüsteemi endasse sisse ehitatud mitmed vahendid süsteemi funktsionaalsuse suurendamiseks - näiteks võimaldab PostgreSQL võtta kasutusele uusi protseduurseid keeli (PL) Näide: Skype – PL/Proxy, Slaidid 6, 11–29 ja arendada laiendusi. Tõeliselt serialiseeritavad transaktsioonid, mis muudab oluliselt lihtsamaks andmete reeglitele vastavuse kontrollimise. Minu arvates parem vastavus SQL standardile. Näiteks Oracles ei saa kasutada nt INFORMATION_SCHEMA skeemi; domeene; BOOLEAN, BIGINT, INTEGER, SMALLINT, DECIMAL andmetüüpe tabelite veergude tüübina; ON UPDATE CASCADE välisvõtme kompenseerivat tegevust. Slaidiettekanne sellest, kuidas PostgreSQLis on konkurentidest parem tugi SQL standardile. EXCLUSION kitsendused koos vahemiku tüüpidega (mida saab ise juurde defineerida) võimaldavad väga lihtsalt jõustada reegleid, et vahemiku tüüpi väärtused ei tohi kattuda (nt kaks broneeringut samasse tuppa ei tohi ajaliselt ei osaliselt ega täielikult kattuda). Serveris saab olla andmebaaside klaster väga suure hulga andmebaasidega, selle asemel, et nagu Oracles jännata alates Oracle versioonist 12.1 allüürnike arhitektuuri toel võimaliku andmebaasile alamandmebaaside defineerimisega. Allüürnike arhitektuuri toe eest tuleb Oracles eraldi litsentsitasu maksta. Enne Oracle 19c ei olnud seda vaja teha kui kasutati eksemplari + konteinerandmebaasi + ühte alamandmebaasi (single-tenant architecture; lone‑PDB architecture). Alates Oracle 19c ei ole seda vaja teha kui kasutusel on kuni kolm alamandmebaasi. Alates Oracle 20c ei ole allüürnike arhitektuuri mittekasutamine enam toetatud (kui just ei olda nõus andmebaasisüsteemi käitama ilma kasutajatoeta). Oracle 21c võib alamandmebaase olla kuni 4098, samas kui PostgreSQLi andmebaaside klastris saab andmebaase olla üle nelja miljardi, kusjuures katsetused näitavad, et suur andmebaaside hulk ei mõjuta PostgreSQLis halvasti operatsioone jõudlust. Väliste andmete pakendajate, väliste serverite ja väliste tabelite funktsionaalsus võimaldab PostgreSQLi andmebaasi abil üles ehitada andmete integreerimise keskkonna. Saan teha nii, et PostgreSQL andmebaasis on tabelid, mille kaudu näen andmeid teistest andmebaasidest ja mille kaudu saan nendes nii andmeid lugeda kui ka muuta. Võimalus koondada andmekirjelduskeele lauseid ühte transaktsiooni, mis lubab teha andmebaasi skeemimuudatusi ühe loogilise tervikuna (kõik laused kas täidetakse, või jäetakse kõik täitmata). Oracles on selleks suurte piirangutega CREATE SCHEMA lause. Plokkide vahemiku indeks - BRIN indeks. Annab B+ puu indeksiga võrreldes väiksema võidu töökiiruses, kuid samas mahult väiksem, kiirem luua ja kiirem uuendada. Oracle analoog - tsoonikaardid (zone maps) - on kasutatavad ainult spetsiaalse riist- ja tarkvara kombinatsiooni korral. Kitsenduste trigerid (constraint triggers), mille protseduuri käivitamise saab lükata transaktsiooni lõppu. Võimaldavad jõustada keerukamaid kitsendusi. Kitsenduste trigerite kasutamine vähendab vajadust lukustada trigeri protseduuris LOCK või SELECT ... FOR UPDATE lausete abil terveid tabeleid või nende üksikuid ridu. Oracle eeliseid võrreldes PostgreSQLiga. Application Express andmetega juhitav veebirakenduste kiirprogrammeerimise vahend. AGA, sellist süsteemi on võimalik realiseerida ka PostgreSQLi põhjal ning seda tõestab selle magistritöö ning selle bakalaureusetöö ja selle bakalaureusetöö tulemus. Rohkem sisseehitatud andmete turvalisuse tagamise vahendeid. AGA, PostgreSQL 9.5 lisandus reapõhiste juurdepääsupiirangute võimalus, st PostgreSQL tõmbab Oraclele selles küsimuses järgi. Hetktõmmiste puhul on võimalik nende osaline värskendamine ning võimalik kohe andmebaasisüsteemis ära kirjeldada nende värskendamise sagedus (ei pea hakkama Cron plaanurit kasutama). Andmebaasisüsteemi sisseehitatud võimalus tööde defineerimiseks ja automaatseks käivitamiseks (töö sisuks võib olla tegevus andmebaasis sh andmebaasiserveris talletatud rutiini käivitamine). PostgreSQL puhul saab kasutada operatsioonisüsteemi utiliiti - Cron plaanurit või tuleb eraldi installeerida mõni andmebaasisüsteemi laiendus nagu näiteks pg_timetable, pg_cron, pgAgent, jpgAgent või pgbucket. Teiste sõnadega, PostgreSQLis tuleb võimaluse kasutusele võtuks teha lisatööd - see ei ole valmiksujul süsteemis olemas. Väiksemad piirangud vaadetele, mille kaudu saab vaikimisi andmeid muuta. Suuremad võimalused mõjutada tabelis olevate andmete salvestamist andmebaasi sisemisel tasemel (sh võimalus koondada tabeleid klastrisse) ja andmete muutmällu lugemist. Selles bakalaureusetöös on mitmete nende Oracle võimaluste kasutamise mõju katsetatud. AGA, PostgreSQL viimastes versioonides pööratakse suurt tähelepanu tabelite sektsioonideks jagamisele (st suure tabeli väiksemateks osadeks jagamisele andmebaasi sisemisel tasemel). Samas on Oracles sektsioonideks jagamine endiselt lihtsam, suuremate võimalustega ja väiksemate piirangutega. Võimalus tabelite denormaliseerimise asemel neid andmebaasi sisemisel tasemel klastrisse koondada (st kasutaja jaoks andmebaasi struktuur ei muutu). Baastabeli veeru tüüpi saab muuta ka siis, kui andmebaasis on loodud vaade, mis viitab sellele veerule. See omakorda lihtsustab andmebaasi evolutsiooni. PostgreSQLis sellisel juhul baastabeli veeru tüüpi muuta ei saa - eelnevalt tuleb vaated kustutada, siis muuta tüüpi ja siis luua vaated uuesti. Võimalus luua (SQL standardis mitte ette nähtud) sünonüüme, mis lihtsustab andmebaasiobjektide ümbernimetamist ja lihtsustab seega andmebaasi evolutsiooni. Bitmap indeks, et kiirendada koondandmete päringuid andmeaitades ja andmevakkades. Suurem hulk sündmuseid (sh näiteks andmebaasi käivitamine, töö lõpetamine, kasutaja sisse- ja väljalogimine), millele reageerimiseks saab luua trigereid. Suund isejuhtivale andmebaasisüsteemile (võimalikult palju administreerimise/disaini oludele vastavalt häälestamise tegevusi automaatselt ning ilma inimkasutaja vahelesegamiseta e autonoomselt) Veel üks võrdlus. Ja veel üks. Konkreetne näide, kuidas suur infosüsteem vahetas Oracle PostgreSQLi vastu. Siin on lühike tekstiline ülevaade. 2019. aasta sügisel teatas Amazon, et lõpetas suuremas osas Oracle andmebaasisüsteemi kasutamise. Läbiviidud andmebaaside migreerimise tulemusena kanti ligi 7500-st Oracle andmebaasist kokku 75 petabaiti andmeid erinevatesse Amazoni enda pilvepõhiste andmebaasisüsteemide abil loodud andmebaasidesse. Mõned kolmandate osapoolte rakendused vajavad tööks ilmtingimata Oracle andmebaase ja need jäid ülekandmata. Sellest migreerimisest kirjutatakse pikemalt siin.Seda, et PostgreSQL on hästi kasutatav suurtes ja kriitilise tähtsusega süsteemides (st ei saa öelda, et Oracle sobib sellistesse süsteemidesse, kuid PostgreSQL ei sobi), näitab näiteks selle andmebaasisüsteemi laialdane kasutamine riigi infosüsteemides. 2018. aastal avaldatud siseministeeriumi haldusala IKT teenuste finantseerimise uuring toob välja, et enamasti on andmebaasisüsteemiks PostgreSQL ja rakendusserveriks Tomcat. Samuti nähti 2019. aasta jaanuari keskel välja kuulutatud sotsiaalkaitse infosüsteemi hanke avalikes dokumentides ette, et uues süsteemis tuleb eelistatult kasutada PostgreSQL andmebaasisüsteemi.Näiteid huvitavatest võimalustest, mida PostgreSQL pakub päringute kirjutajatele on SIIN. Lõpetuseks tõstaksin esile Markus Winandi (mees veebilehe taga modern-SQL, mis tutvustab kaasaegset SQLi kogu oma vägevuses) kiidusõnu PostgreSQLi aadressil: Küsimusele kuidas Teile meeldib PostgreSQL vastas ta nii: "PostgreSQL on väga tugevas positsioonis. Arendajate vaatepunktist on selle pakutavad võimalused lähemal kommertssüsteemidele kui avatud lähtekoodiga võistlejatele nagu MySQL/MariaDB. Mulle meeldib eriti PostgreSQLi pakutav rikkalik SQL standardi toetus, mis tähendab selliseid asju nagu täielik VALUES klausli toetus, rekursiivsed päringud, over, lateral ja massiivide kasutamise võimalus." Ühes teises kohas vastas ta küsimusele, millist andmebaasisüsteemi ta eelistab, et kõik sõltub nõuetest, arendusmeeskonnast ja eelarvest, kuid kui need pole veel selged, siis on PostgreSQL parim vaikimisi valik. ## Küsimus: Milliseid raamatuid soovitate erinevate andmemudelite kohta (andmemudel kui andmebaasikeele aluseks olev üldiste andmebaasi ehitusplokkide, kitsenduse tüüpide, andmetüüpide ja operatsioonide kirjeldus)? **Vastus:** Relatsiooniline andmemudel (mitte ajada segi SQLiga)Date, C.J., 2015. SQL and Relational Theory, 3rd Edition. O'ReillyDate, C.J., Darwen, H., 2007. Databases, types, and the relational model. 3rd ed. China Machine Press Sama raamat on saadava füüsilisel kujul ülikooli raamatukogust.NoSQL süsteemid Sadalage, P.J., Fowler, M., 2013. NoSQL distilled : a brief guide to the emerging world of polyglot persistence. Upper Saddle River (N.J.)Sama raamat on saadava füüsilisel kujul ülikooli raamatukogust. Dokumendipõhistel ja graafipõhistel andmemudelitel põhinevad andmebaasisüsteemid kuuluvad NoSQL süsteemide kategooriasse. Nendest mudelitest annab teises peatükis ülevaate: Kleppmann, M., 2017. Designing Data-intensive Applications : the Big Ideas Behind Reliable, Scalable, and Maintainable Systems, O'Reilly. 590 p.Sama raamat on saadava füüsilisel kujul ülikooli raamatukogust. Graafipõhiste andmemudelite kohta saab lugeda eesti keeles jaotisest 2.2: Mikk, S.M., 2017. Graafide esitamine SQL-andmebaasides. Magistritöö. TTÜ Tarkvarateaduse instituut.Kuidas kasutada O'Reilly digitaalset platvormi? ## Küsimus: NoSQL süsteemid, sh MongoDB on "uus lahe tehnoloogia". Mida ma võiksin nende kohta teada? **Vastus:** Kasutage, kui vaja, kuid olge tähelepanelikud ja säilitage kriitiline meel. Siin on Teile veidi mõtteainet edasiseks eluks. 2024. aasta augustis oli MongoDB andmebaasisüsteemide populaarsuse indeksis viiendal kohal! Kui mitte muul põhjusel, siis laske pilk hetkeks sellest artiklist üle, nägemaks, kuidas andmete hajutatud paiknemine komplitseerib süsteemide käitumist. See artikkel on osa projektist Jepsen, mis testib erinevaid hajussüsteemide loomiseks mõeldud vahendeid. Tsitaat: "In this post, we’ll see that Mongo’s consistency model is broken by design: not only can “strictly consistent” reads see stale versions of documents, but they can also return garbage data from writes that never should have occurred. The former is (as far as I know) a new result which runs contrary to all of Mongo’s consistency documentation. The latter has been a documented issue in Mongo for some time. We’ll also touch on a result from the previous Jepsen post: almost all write concern levels allow data loss." Mis on sellise või teiste samalaadsete süsteemide kasutamise tulemus? NoSQL Meets Bitcoin and Brings Down Two Exchanges: The Story of Flexcoin and Poloniex. Tsitaat ühest teisest artiklist, mist käsitleb MongoDB pakutavaid päringute tegemise võimalusi: "Instead of providing developers with a core, well-engineered set of properly shaped building blocks that can combine together to solve all problems, MongoDB provides a set of weirdly shaped, poorly connecting blocks that solve whatever ad hoc user problems prompted their development." Lõpetuseks veel mõtteavaldusi MongoDB kohta. Pange tähele, et paljudel arvajatel leidub häid sõnu PostgreSQLi kohta. Maailma esimene süsteem, mis brändis ennast nime all NoSQL pole päris see, mida ootate/arvate. NoSQL süsteemide õppimise ja kasutamise häda on, et (hetkel veel) on vähe standardeid, mida kõik süsteemid peaksid järgima. Standardite puudus on NoSQL süsteemide autorite teadlik valik - standardid olevat liiga piiravad. Nende meelest - parim süsteem võitku. Kui ellujäänud on selginud ja tehnoloogia areng stabiliseerub, siis võivat ka hakata mõtlema standarditele. Dokumendipõhiste süsteemide (nagu MongoDB) puhul on standardiks JSON formaati kirjeldav standard. JSON formaati kasutavad dokumendipõhised andmebaasisüsteemid pakuvad võimalust kontrollida/tagada, et andmebaasis andmeid esitav JSON dokument on trimmis, st reeglitega kooskõlas. Graafi andmebaasisüsteemide korral on jõutud selleni, et populaarseima graafipõhise andmebaasisüsteemi Neo4j arendajad esitasid üleskutse töötada välja graafipõhise andmebaasikeele standard (võttes muidugi aluseks Neo4j andmebaasikeele Cypher). 2019. aasta suvel algatas ISO (International Organization for Standardization) kõigi rahvuslike standardimise organisatsioonide seas küsitluse, kas alustada GQL (Graph Query Language) standardi loomist. 2019. aasta septembris kiideti standardi loomisega alustamine heaks ning standardi esimene heakskiidetud redaktsioon avaldati 17. aprillil 2024 - https://www.gqlstandards.org. GQL pärib mõned omadused (andmetüübid, avaldised jne) SQList, viidates selleks SQL standardile. Praktikas tähendab standardite puudus, et igas süsteemis on oma andmebaasikeel. Kui isegi süsteemides X ja Y on justkui ühesugune andmemudel (nt graafi andmemudel), siis lähemal vaatlusel selgub, et nende süsteemide arendajate nägemus sellest andmemudelist võib olla märkimisväärselt erinev. Andmebaasisüsteemide võimaluste hulgas ja käitumises esineb väga suuri erinevusi. Standardite puudus tähendab, et kui hakata tarbijana kasutama süsteemi X ning aasta-paari pärast seda arendav (idu)firma pillid kotti paneb, siis uuele platvormile ülekolimine võib osutuda keeruliseks ja töömahukaks. Samuti tähendab standardite puudus, et süsteemi kasutada oskavaid spetsialiste on raske leida ja kallis pidada. Sisuliselt on igal süsteemil oma "standard" ja seda olukorda kirjeldatakse naerdes läbi pisarate SIIN. Tõele au andes - olemas on SQL standard, kuid ka ühe SQL-andmebaasisüsteemi vahetamine teise vastu (andmebaasi migratsioon) on paraku endiselt keeruline ja töömahukas ülesanne. Seega standard pole imerohi - need kellele standard on mõeldud peavad seda ka reaalselt järgima hakkama. Kui tahate kiiret kõrgtaseme ülevaadet NoSQL süsteemides, siis on see päris hea materjal. Sama mees on üks selle raamatu autoritest ja viidatud artikkel on põhimõtteliselt selle raamatu lühikokkuvõte. Nimetatud raamatut saab ka lugeda elektrooniliselt O'Reilly digitaalse platvormi kaudud SIIN (Kuidas kasutada O'Reilly digitaalset platvormi?). ## Küsimus: PostgreSQL ja Oracle pakuvad funktsioone, mis realiseerivad foneetilisi algoritme. Milleks neid vaja on? Mis nendest kasu on? **Vastus:** Foneetilisi algoritme saab kasutada näiteks suguvõsauuringutes, et otsida sarnase kõlaga perekonnanimega inimesi. Need inimesed võivad, aga ei pruugi, olla omavahel sugulased. Võibolla panid dokumentide väljaandjad vanal ajal nime kirja kuulmise järgi ning seetõttu on erinevate inimeste nimed sarnase kõlaga, kuid erineva kirjapildiga. Sarnase probleemiga puutuvad kokku paljud ajaloouurijad. Toon näiteks tsitaate: "Omaette tõsiseks probleemiks on isikunimede moonutamine vene keelde transkribeerimisel, kuna nimed said tihti üleskirjutatud vaid kuulmise järgi." (Rajaotsinguid - Sõjavangilaagrite dokumendid ajalooallikaina). "Kalmisturaamatusse kanti andmeid sageli mitte dokumendi alusel vaid kuulmise järgi, seega võis viga olla juba kalmisturaamatus" (allikas). Soundex algoritmi kasutatakse mõnedes (ingliskeelsetes) riikides piiriturvalisuse tagamisel. Inimesel võib olla võltsitud dokument, millel kasutatakse tema pärisnimele (mis võib olla huvipakkuvate isikute nimekirjas) kõlalt lähedast nime. See võib viia väga kummaliste tagajärgedeni nagu kirjutatati siin juba tükk aega tagasi. Siin on veel kriitikat Soundex'i ebatäpsuse suhtes. Näiteks ei ole see võimeline arvestama olukorraga, et erinevates keeltes võib sama nimi teiseneda nii palju, et neil on erinevad Soundex'i koodid. Soundex on koostatud inglise keelt silmas pidades ja ei suuda arvestada teiste (nt erinevate Aasia keelte) kultuuriliste omapäradega. Foneetilisi algoritme saab ka kasutada, et otsida ühes ja samas süsteemis või üle erinevate süsteemide inimesi, kes esinevad ja teevad seal tegusi veidi erinevate nimede all (nt broneerivad mitme erineva, kuid üsna sarnase nime all lennupileteid). Veel üheks näiteks on, et süsteemis, kus klient ei pea tellimuse tegemiseks ennast identifitseerima, vaid sisestab iga kord isikuandmed uuesti, võib ta erinevate tellimuste puhul kogemata või meelega teha nime sisestamisel vea. Mõnda foneetilist algoritmi realiseerivat funktsiooni kasutava päringu abil saab need erinevad tellimused omavahel "kokku viia". ## Küsimus: Tooge palun mõni andmebaasisüsteemi poolt tehtava semantilise teisenduse näide?! **Vastus:** Andmebaasisüsteemi poolne päringu lihtsustamine tähendab, et andmebaasisüsteem asendab kasutaja poolt ette antud päringu lihtsama, kuid alati samasuguse tulemuse andva päringuga (loogiliselt samaväärse päringuga) ja täidab selle uue päringu. Lihtsama päringu täitmine peaks toimuma kiiremini.Suur klass lihtsustusi põhineb andmebaasis deklareeritud kitsendused. Andmebaasisüsteem saab teha selliseid lihtsustuse teisendusi, kuna saab tänu jõustatud kitsendustele andmete kohta midagi eeldada. Kuna kitsendused kirjeldavad andmebaasisüsteemi jaoks andmete tähendust (semantikat), siis nimetatakse selliseid lihtsustusi semantilisteks teisendusteks. Üheks selliseks teisenduseks on tabeli elimineerimise teisendus (table elimination transformation, join elimination transformation), mida oskavad suuremal või vähemal määral teha mitmed SQL-andmebaasisüsteemid sh PostgreSQL ja Oracle. See teisendus tähendab, et kui päringus ühendatakse tabelit, mida päringu tulemuse saavutamiseks pole tegelikult vaja lugeda, siis jäetakse see ühendamisoperatsioon ära ja eemaldatakse päringust viited sellele ühendatavale tabelile.Näide (tabelite loomise laused on Oracle andmebaasisüsteemi jaoks).CREATE TABLE Isik (isik_id NUMBER(10),e_meil VARCHAR2(254) NOT NULL,eesnimi  VARCHAR2(1000) NOT NULL,perenimi VARCHAR2(1000),CONSTRAINT pk_isik PRIMARY KEY (isik_id),CONSTRAINT ak_isik_e_mail UNIQUE (e_meil));CREATE TABLE Tootaja (isik_id NUMBER(10),CONSTRAINT pk_tootaja PRIMARY KEY (isik_id),CONSTRAINT fk_tootaja_isik FOREIGN KEY (isik_id) REFERENCES Isik (isik_id) ON DELETE CASCADE);CREATE TABLE Tuba (tuba_kood NUMBER(10),registreerija_id NUMBER(10) NOT NULL,CONSTRAINT pk_tuba PRIMARY KEY (tuba_kood),CONSTRAINT fk_tuba_tootaja FOREIGN KEY (registreerija_id) REFERENCES Tootaja (isik_id));Iga töötaja on ühtlasi isik. Tänu andmebaasi struktuurile ja jõustatud kitsendustele on tagatud, et iga tabelis Tuba olev registreerija_id väärtusele vastab isik_id väärtus tabelis Isik.Järgnev päring ühendab kokku tabelites Isik, Tootaja ja Tuba olevad andmed. Tabelist Tootaja ei väljastata andmeid ühestki veerust. Päringu tulemust ei piirata tabelis Tootaja olevate andmete alusel. SELECT e_meil, eesnimi, perenimi, tuba_koodFROM Isik INNER JOIN Tootaja ON Isik.isik_id=Tootaja.isik_idINNER JOIN Tuba ON Tuba.registreerija_id=Tootaja.isik_id;See päring on loogiliselt samaväärne järgneva päringuga.SELECT e_meil, eesnimi, perenimi, tuba_koodFROM Isik INNER JOIN Tuba ON Tuba.registreerija_id=Isik.isik_id;Kas andmebaasisüsteemid oskavad esimest päringut lihtsustada, et see oleks nagu teine päring? Oracle 12c Enterprise Edition Release 1 oskab (vt vastusele lisatud päringu täitmisplaani pilti - loetakse tabeleid Tuba ja Isik, kuid mitte Tootaja). PostgreSQL 14 ei oska (vt vastusele lisatud päringu täitmisplaani pilti - loetakse nii tabeleid Tuba, Tootaja kui ka Isik). Mida sellest järeldada. Oracle oskab tabeli elimineerimist paremini kui PostgreSQL. Päringu kirjutaja peab olema tähelepanelik ja ka ise päringuid lihtsustama - mitte jätma seda andmebaasisüsteemi hooleks. Andmebaasisüsteem võib kuid ei pruugi osata seda lihtsustada. Lisaks on lihtsamat koodi ka inimestel lihtsam lugeda, muuta ja sellest aru saada. ## Küsimus: Töökiiruse tõstmiseks ei kirjuta andmebaasisüsteemid andmemuudatusi kohe kettale, küll aga kirjutavad kohe kettale andmemuudatuse kohta käiva logi. Kuidas see töökiirust tõstab? Logi kirjutamine on ju samuti kõvaketta poole pöördumine. Kirjeldasite, et bloki kettale salvestamisel kustutatakse see muutmälust ära. Seega proovid süsteem salvestamist edasi lükata, kuna blokki võib kohe järgmistes päringutes jälle vaja olla ning oleks hea, kui see oleks muutmälus olemas. Miks mitte blokki kettale kirjutada, kuid jätta see ka muutmällu alles? **Vastus:** Logi kirjutamine enne muudatusi sisalduvate plokkide (räpaste plokkide) kettale kirjutamist pakub paindlikust, sest andmebaasisüsteem saab nende plokkide kettale kirjutamist edasi lükata ja valida selleks selleks endale sobivaima aja. Meetodit, kus enne andmemuudatuste kettale kirjutamist kirjutatakse alati kettale muudatuste logi, nimetatakse Write-Ahead Logging (WAL).PostgreSQL dokumentatsioon kirjutab: WAL kasutamine viib märkimisväärselt väiksema hulga kettale kirjutamisteni (ajal kui serveril on suur koormus), sest transaktsiooni tulemuste püsiva salvestamise tagamiseks (D omadus transaktsioonide ACID omadustest) piisab logi kettale kirjutamisest ja ei ole vaja (kohe) kettale kirjutada muudetud plokke. Logifaili kirjutatakse järjestikuliselt (uus logi läheb kõige lõppu) ja see maksab palju vähem, kui muudetud plokkide kettalt üles otsimine (need võivad olla erinevates ketta piirkondades) ja uue versiooniga asendamine. See kehtib eriti serverite puhul, mis peavad toime tulema paljude väikeste andmete muutmise transaktsioonidega, kusjuures muudetavaid andmeid sisaldavad plokid on kettal füüsiliselt laiali. Paljude samaaegsete väikeste transaktsioonide korral võib üks logi kettale kirjutamine (üks kord fsync() funktsiooni täitmine) kirjutada kettale korraga logi paljude transaktsioonide kohta.Kogu andmebaasi töö ajal muutmälus hoidmine (in-memory database)  on üks töökiiruse parandamise meede, mida uue põlvkonna andmebaasisüsteemid kasutavad. Piirid seavad ette andmebaasi andmemaht ja serveri muutmälu suurus. Enamik andmebaasisüsteeme toimib ikkagi niimoodi, et muutmälus on töö ajal vaid osa andmebaasist. Uutele andmetele ruumi tegemiseks kasutatakse näiteks Least-Recently Used algoritmi, st esimesena kustutatakse muutmälust plokid, mille viimasest kasutamisest on möödas kõige rohkem aega. --- # Teema: CASE vahendid ## Küsimus: Kas võin kasutada Rational Rose CASE vahendis # märke? **Vastus:** Ühel üliõpilaste grupil oli probleem Rational Rose andmebaasi disaini mudeli riknemisega. Probleem (vähemalt ajutiselt) kadus, kui mudelis eemaldati skeemi (schema) nimest ##. Seega palun ärge igaks juhuks kasutage skeemi nimedes # märke. Näiteks skeemi nime C##TUD5 asemel kasutage nime TUD5. ## Küsimus: Kuidas parandada Enterprise Architect CASE vahendis loodud andmebaasi disaini mudelis riknenud tabelite vahelist seost? **Vastus:** Vaadake palun SEDA videot või vastusele lisatud faili.Kui vaatamata kõigele ei õnnestu seose kirjeldust parandada, siis jätke see nii nagu on ja tehke parandus genereeritud SQL koodis. **Märksõnad:** välisvõti, foreign key ## Küsimus: Kuidas teha nii, et Enterprise Architect vahendis ei genereeritaks PostgreSQL andmebaasi disaini mudeli põhjal koodi, mida peab käsitsi parandama? **Vastus:** Tuleb muuta malle (template), mille põhjal koodi genereeritakse. Malle tuleb muuta eraldi iga faili puhul, milles olevast mudelist soovitakse koodi genereerida.Järgnevad probleemid esinevad EA12-ga vaikimisi kaasa tulevates mallides. EA16 korral on genereeritud koodis tabelite, kitsenduste ja indeksite nimed jutumärkides, kuid veergude nimed ei ole. SERIALiga seotud probleemi EA16 genereeritud koodis ei esine. TIME ja TIMESTAMP tüüpide puhul täpsuse 0 mitte arvestamine esineb nii EA12 kui EA16 korral.Mallide vaatamiseks ja muutmiseks valige Package=>Database Engineering=>Edit DDL TemplatesSeejärel valige liitboksist Language andmebaasisüsteem - antud juhul PostgreSQL. Malli muutmise järel tuleb salvestamiseks selle juures vajutada Save nupule või vajutada Ctrl+S.1. Kuidas teha nii, et genereeritud koodis poleks andmebaasiobjektide identifikaatorid e nimed jutumärkides? Näiteks lause CREATE TABLE "Riik" (... asemel tahaksin lauset CREATE TABLE Riik (....Valige mall DDL Left Surround ja kustutage sealt jutumärk ("). Ärge ridu kustutage.Valige mall DDL Right Surround ja kustutage sealt jutumärk ("). Ärge ridu kustutage.2. Kuidas teha nii, et genereeritud koodis poleks SERIAL veeru korral eraldi arvujada generaatori loomist, veeruga sidumist ja siis ka arvujada generaatori kustutamist? SERIAL notatsiooni e tähistuse kasutamise korral toimub see kõik ju automaatselt.Näiteks koodiDROP SEQUENCE IF EXISTS isik_isik_id_seq;CREATE TABLE Isik(    isik_id serial NOT NULL DEFAULT nextval(('isik_isik_id_seq'::text)::regclass),...);CREATE SEQUENCE isik_isik_id_seq INCREMENT 1 START 1;asemel soovin koodiCREATE TABLE Isik(    isik_id serial NOT NULL,...);Selleks laadige alla selle vastusega seotud fail ning muutke oma mudelifailis järgmised mallid selliseks nagu need on selles failis. Jälgige, et iga malli lõpus oleks tühi rida. Need uued malli versioonid on võetud EA 16 vahendist. Kui klõpsate EA-s mallide nimekirjas veerul Name, siis saate need tähestiku järgi sorteerida. DDL Column Definition DDL Column Extras DDL Create Sequence DDL Drop Column Extras DDL Drop Sequence DDL Script File 3. Kuidas teha nii, et genereeritud koodis oleks TIME ja TIMESTAMP tüüpide korral arvestatud mudelis määratud täpsusega 0, mis tähendab, et sekundi murdosasid ei registreerita?Näiteks koodi CREATE TABLE Isik(    reg_aeg timestamp without time zone NOT NULL DEFAULT LOCALTIMESTAMP(0),...);asemel soovin koodiCREATE TABLE Isik(    reg_aeg timestamp(0) NOT NULL DEFAULT LOCALTIMESTAMP(0),...);Selleks laadige alla selle vastusega seotud fail ning muutke oma mudelifailis mall DDL Data Type selliseks nagu see on selles failis. Jälgige, et malli lõpus oleks tühi rida. Kui klõpsate EA-s mallide nimekirjas veerul Name, siis saate need tähestiku järgi sorteerida. **Märksõnad:** koodi genereerimine, SQL, CREATE TABLE, jutumärgid ## Küsimus: Kustutasin Enterprise Architecti andmebaasi disaini mudelis välisvõtme veerule loodud indeksi, sest sellel veerul on juba primaarvõtme või unikaalsuse kitsenduse toetuseks automaatselt loodud indeks. Hiljem avastasin, et see indeks on tagasi tekkinud? Miks see nii on ja kuidas seda vältida? **Vastus:** Vastusele lisatud joonises on näidatud Enterprise Architecti välisvõtme kirjeldamise akent. Seal on tähistatud koht Enterprise Arechitectis, kus saab määrata, kas välisvõtme veerule tuleks luua indeks.Kui näiteks kustutate välisvõtme veerul indeksi, mis langeb kokku primaarvõtme indeksiga, seejärel muudate välisvõtme kitsenduse omadusi selle akna kaudu ja selles aknas on Create?=True, siis pannakse see indeks tagasi.Lahenduseks on määrata Create?=False **Märksõnad:** Enterprise Architect, välisvõti, võõrvõti, andmebaasi disaini mudel ## Küsimus: Lõin ühenduse virtuaalse töölauaga ning seadistasin failide jagamise, kuid virtuaalsel töölaual ei ilmu minu kohaliku arvuti kataloogid nähtavale. Mida teha? **Vastus:** Kui olite virtuaalsele töölauale sisseloginud, siis muudatuste rakendamiseks logige virtuaalselt töölaualt välja ja uuesti sisse, mitte ärge valide ristile vajutades "Disconnect". **Märksõnad:** Horizon, virtuaalne töölaud, vmware, kaug, kaugtöö ## Küsimus: Ma ei suuda Enterprise Architect (EA) vahendi menüüde rägastikus orienteeruda. Millised on kõige olulisemad menüüpunktid antud aine jaoks? **Vastus:** Järgnevalt on nimetatud EA12 näitel mõnede oluliste funktsioonide asukoht menüüsüsteemis. Tööriistakast, kust saab valida mudelisse lisamiseks uusi elemente. Kui olete selle kinni pannud, siis saate uuesti avada: Diagram=>Toolbox (kiirkorraldus ALT+5) Projekti elementide hierarhia. Kui olete selle kinni pannud, siis saate uuesti avada: View=>Project Browser (kiirkorraldus ALT+0) SQL koodi genereerimine: Package=>Database engineering=>Generate package DDL ## Küsimus: Mida teha, kui arvutiklassi arvutis küsib Enterprise Architect (EA) avamisel võtit ja ei ole nõus ilma selleta käivituma? **Vastus:** Sulgege EA. Valige: Control Panel => System and Security => Configuration Manager => Configurations => evaluate CB WRK Enterprise Achitect Key Seejärel avage EA uuesti. **Märksõnad:** litsents, värskendamine, laenutamine, arvutiklass ## Küsimus: Mida teha, kui Horizoni virtuaalsel töölaual küsib Enterprise Architect (EA) avamisel võtit ja ei ole nõus ilma selleta käivituma? **Vastus:** EA kasutamiseks peab peale sisselogimist hetke ootama, et skriptifail looks vajalikud registri võtmed selle jaoks. Config Manageri (mille kaudu käib võtmete laenutamine arvutiklassi arvutis) nendes masinates pole ja Horizoni loomuse tõttu ei hakka ka olema. **Märksõnad:** Horizon, virtuaalne töölaud, VDI-Andmebaasid, vmware, ICT-Class, ICT-Classroom, kaug, kaugtöö ## Küsimus: Milliseid võimalusi pakub Enterprise Architect andmebaaside projekteerijale? **Vastus:** Video Enterprise Architect 12 täiendustest seoses andmebaaside arendamisega. ## Küsimus: Mul on arvutiks Mac / minu arvutil on Linux operatsioonisüsteem. Kuidas saan kasutada Enterprise Architect (EA) CASE vahendit? **Vastus:** Ülikooli pakutav Enterprise Architect (EA) 12 on mõeldud Windowsile. EA14 näitel näen, et seda saab installeerida ka Maci, kuid see nõuab üsna palju lisatööd. Litsentsi taotlemine (bat failiga) on mõeldud just EA12 jaoks, st seda ei saa kasutada näiteks EA kodulehelt allalaaditud kõige viimasele EA versioonile litsentsi taotlemiseks. Maci/Linuxi kasutajad saaksid enda arvutis EA tööle nii, et panevad seal paralleelselt tööle Windowsi (Internetist leiab juhiseid; panin siia stiilinäiteks ühe juhise Maci ja ühe Linuxi kohta). Azure Dev Tools for Teaching keskkonnast on võimalik saada Windows Server operatsioonisüsteem. Alternatiivid on järgmised. Kasutada virtuaalset töölauda. Juhendi leiab SIIT. Tuleb valida virtuaalne töölaud  Andmebaasid või ICT-Class. Lahendus töötab ka väljastpoolt ülikooli. Hetkel ei ole sellisel juhul eelnevalt vaja luua FortiClient VPN ühendust, aga see võib jooksvalt muutuda, kui administraatorid tunnevad, et on vaja lisada eraldi turvakiht. Teenus töötab vajadusel veebilehitsejas. Lisaks Windowsile on olemas kliendid nii Linuxile kui Macile ning tegelikult isegi Android ja iOS jaoks. Samuti saate seda lahendust kasutada, kui olete oma Linux/Mac arvutiga arvutiklassis. NB! Kindlasti on vaja teha vastavalt juhendile ketta jagamine, sest välja logides kustutatakse loodud failid kohe (sh kataloogist PrivatData). Kui sulgete Horizon akna ristist, siis loodud töölaud ja failid säilivad 15 minutit. Kui kasutate veebipõhist lahendust, siis saab virtuaalsele töölauale faile üleslaadida. Kuid failide kättesaamiseks tuleks logida VDI masinast näiteks OneDrive'i. Seega on soovitatav kasutada klientprogrammi ning veebilehitseja jätta pigem hädajuhtudeks. EA kasutamiseks peab peale sisselogimist hetke ootama, et skriptifail looks vajalikud registri võtmed selle jaoks. Config Manageri (mille kaudu käib võtmete uuesti laenutamine arvutiklassi arvutis) nendes masinates pole ja Horizoni loomuse tõttu ei hakka ka olema. Installeerida EA12 oma Windowsi lauaarvutisse (tööl või kodus) ning taotleda litsentsi üle FortiClient VPNi. Koolis saab EAd kasutada arvutiklassi arvutites. EAd läheb vaja projekti tegemise ülesannete 2-4 jaoks (kokku on ülesandeid 12). Hindan, et EA osa projektist on täiesti võimalik valmis teha praktikumide jooksul kohapeal. Alternatiiv Enterprise Architect / Rational Rose CASE tarkvara kasutamisele on kõigepealt luua tabelid (arvestades endiselt ülesannetes 2-4 olevaid soovitusi/juhiseid) ja siis kasutada mõnda vahendit nende ülesehituse visualiseerimiseks (vt seda küsimust PostgtreSQL kohta; Oracle tabelite visualiseerimiseks saab kasutada Oracle SQL Developer Data Modeler tarkvara). **Märksõnad:** kaugkasutus, virtuaalne töölaud, Horizon, vmware, virtuaalmasin, virtuaal, desktop, vpn, kaug, kaugtöö ## Küsimus: Rational Rose (RR) või Enterprise Architecti (EA) mudelifail riknes. Selle väljenduseks on, et mudeli (kas kõiki või osasid) elemente ei saa enam muuta ning ei saa genereerida tabelite kirjeldusest SQL lauseid. Mida teha? **Vastus:** Tõepoolest, paraku nii RR kui EA failidega võib selline paha asi juhtuda. Tehke palun iga kord enne mudeliga tööle hakkamist failist koopia ja tehke tööd koopias. Originaal nimetage ümber ja säilitage. Kui töö käigus selgub, et fail on riknenud, siis originaal on alles ja kaotsi ei lähe kogu töö, vaid ainult viimasel korral tehtu. ## Küsimus: Sain Enterprise Architectis (ver 12) veateate "Unrecognized database format". Viga tekkis peale seda, kui olin kõigile tabel X veergudele vajalikud check kitsendused kirjeldanud ja tahtsin edasi liikuda järgmise registri juurde. Proovisin jätkata teises arvutis, kuid jõudsin sama tulemuseni - peale tabeli X kõigile veergudele check kitsenduste kirjeldamist kordus sama viga. Mida teha? **Vastus:** Enterprise Architecti dokumentatsioon kirjutab: "Unfortunately on rare occasions usually caused by network or PC outages a .EAP may become corrupted and may not be opened." Küsimuses tõstatatud EA probleem lahenes järgnevalt. Avasin Enterprise Architecti. Kui tarkvara küsis, milline projekt avada, siis vajutasin "Cancel". Seejärel valisin: Project => Data Management=> Manage .EAP File => Repair .EAP File Avanenud aknas valisin probleemidega EA faili. Seejärel ootasin mõned minutid kuni tarkvara faili töötles. Peale seda õnnestus fail avada. ## Küsimus: Teen Enterprise Architectis topeltklõpsu tabelite vahelisel seosel ning saan veateate, et osalevad tabelid on erinevates andmebaasisüsteemides. Milles on probleem ja kuidas seda parandada? **Vastus:** Vaadake lisatud faili. **Märksõnad:** Enterprise Architect ## Küsimus: Üritan Mauruse keskkonnas taotleda uut Enterprise Architect programmi litsentsi. Olen bakalaureuseõppes EA litsentsi juba taotlenud, seega saan veateate, et "Te olete seda ressurssi juba taotlenud". Mida teha? **Vastus:** Uuesti ei saagi taotleda, sest üks taotlus on olemas, rahuldatud ja endiselt kehtiv. Pääsete rahuldatud taotlustele vastavatele failidele ligi "Minu taotlused" alt. Sealt saate nii failid, millega EA enda arvutisse installeerida kui ka litsentsi taotlemiseks mõeldud bat faili. Tallinna Tehnikaülikooli ruumides saab laenutamist teha üle Wi-Fi. Väljaspool ülikooli tuleb enne laenutamist luua FortiClient VPN ühendus. Litsentsi aegumise järel tuleb laenutamist korrata. Veenduge, et Enterprise Architect (EA) on suletud, käivitage bat fail ning avage EA, veendumaks, et litsents on laenutatud ning programm avaneb. **Märksõnad:** vpn --- # Teema: Infosüsteemid ja nende arendus (Üldine) ## Küsimus: Kas leidub eestikeelset materjali tehnilise võla kohta? **Vastus:** Käosaar, E., 2017. Lähtekoodi halbade lõhnade üldistamine süsteemianalüüsi mudelitele. Bakalaureusetöö. TTÜ Tarkvarateaduse instituut. [WWW] https://digi.lib.ttu.ee/i/?8930 Paide, R., 2017. Juhtumiuuring tehnilisest võlast Eesti IKT sektori ettevõtetes. Magistritöö. TTÜ Tarkvarateaduse instituut. [WWW] https://digi.lib.ttu.ee/i/?8865 Siseministeerium, 2018. Siseministeeriumi haldusala IKT teenuste arendamine ja haldamise finantseerimise jätkusuutlikkus ning mõju siseturvalisuse tagamisele. Lõpparuanne. 17.08.2018 [WWW] https://www.smit.ee/files/ikt-finantseerimine-pwc-lopparuanne-veeb.pdf?a8072e9c5b Käosaar (2017) kirjutab tehnilise võla vähendamisest süsteemianalüüsi mudelites. Ta esitab kataloogi mudelites esinevatest halbadest lõhnadest. Iga sellise lõhna esinemine võib olla mudelites leiduva tehnilise võla tunnus. Paide (2017) uurib tehnilise võla fenomeni Eesti IT ettevõtetes. Selleks viidi läbi poolstruktureeritud intervjuud kaheksa ettevõtte esindajatega (33-st kutsutust). Intervjueeritud töötasid erinevatel IT arendusega seotud töökohtadel. Nad kõik väitsid, et on tehnilise võla mõistega kursis. Intervjuude tulemusi uuriti erinevate statistiliste meetoditega. Tehnilise võla küsimustele pöörab tähelepanu ka siseministeeriumi haldusala IKT teenuste finantseerimise uuring (Siseministeerium, 2018). Selle uuringu teise peatüki pealkiri on "Tehnoloogiline võlg teenustes". Uuringu lõpparuanne on huvitav ka seetõttu, et seal kirjeldatakse ühte võimalikku tehnilise võla leidmise ja suuruse arvutamise metoodikat. Seda metoodikat kasutati siseministeeriumi haldusalas olevate IT teenuste tehnilise võla suuruse väljaarvutamiseks. Uuringus osales siseministeeriumi haldusalast 14 meeskonda, mis haldavad 45 IT teenust. Uuringu tulemusena leiti uuritud tarkvarades ja nende toimimiseks vajalikes platvormides lähtekoodiga seotud tehniline võlg, mille likvideerimine või tasandamine nõuab pingutust vähemalt u 71100 tarkvaraarendaja töötunni ulatuses. Sellest tarkvaraplatvormidega seotud parandused oleksid 50600 töötundi ja tarkvara lähtekoodi parandused 20478 tundi. ## Küsimus: Kas oskate tuua näiteid Eestist andmete turvalisuse rikkumise kohta? **Vastus:** 15.01.2017 Postimehes oli Nils Niitra artikkel andmelekkest metsaregistris. See on surepärane juhtumianalüüs teema 5 (andmete turvalisus) kohta. Niitra (2017) kirjutab metsaregistrist toimunud andmelekkest. Väidetavalt luges üks artikli kirjutamise ajaks töölt lahkunud töötaja süstemaatiliselt infot isikute (nimed, sünniajad, telefoninumbrid) ja nende metsakinnistute kohta. Peale töölt lahkumist asus ta tööle erafirma metsakorraldajana. Lekkinud info alusel hakkasid metsaomanikud saama massiliselt telefonikõnesid, millega üritati neid kallutada müüma raieõigust turuhinnast madalamalt. Vahendusfirmasid huvitab põhiliselt raieõigus. Seda müüakse suure vaheltkasuga edasi metsa ülestöötamisega tegelevatele ettevõtetele. "Samad firmad tegelevad ka kinnistute vahendamisega rahvusvahelistele kontsernidele, Eesti kohalikele suurmaaomanikele ja välismaistele pensionifondidele. Mets saadakse inimestelt kätte muuhulgas neid juriidiliselt korrektsel moel pettes, kasutades selleks väga erinevaid võtteid." (Niitra, 2017) Olgu öeldud, et avaliku teabe seadus keelab riigi infosüsteemis asutada ühtede ja samade andmete kogumiseks eraldi andmekogusid. Isikuandmete kogumise koht on rahvastikuregister. Metsaregistrisse jõuavad isikuandmed siis, kui inimesed esitavad e-kava keskkonna kaudu metsaregistrile enda metsa kohta infot. Milliseid seoseid saab tõmmata selle juhtumi ja andmebaaside aines õpitu vahele? Andmete loata lugemine rikkus konfidentsiaalsuse nõuet. Kuna metsaregister ei loginud piisavalt infot selle kohta, kes ja milliseid andmeid täpselt luges ning milliseid tegevusi andmetega tegi (kas laadis alla või mitte), siis polnud täidetud ka revideeritavuse nõue. "Asutusesisese uurimise käigus suudeti küll tõestada, et mees oli käinud andmeid vaatamas, küll aga oli võimatu tagantjärele kindlaks teha, kas ta neid ka maha laadis." – puudus võimalus viia läbi turvarikke tõendtuvastus, mida on vaja turvarikete rangeks ja täpseks tõestamiseks (näiteks, et oleks võimalik kasutada süüdistusmaterjalina kohtus). Töötaja vaatas andmeid, mis ei kuulunud tema tööpiirkonda – õiguste jagamisel ei oldud lähtutud minimaalsuse printsiibist. Registri kasutamise paroolid on antud ka metsakonsulentidele. Neil võib tekkida huvide konflikt, kuid kuna andmete lugemisi piisavalt ei logita, siis on võimatu seda tuvastada. Võimalik, et süsteemile juurdepääsu andmisel pole lähtutud minimaalsuse põhimõttest ja juurdepääs on antud liiga suures ulatuses liiga laiale kasutajate ringile. Riiklike registrite andmete avalikustamine suurendab üheltpoolt läbipaistvust, kuid teisalt võib leiduda selle info kuritarvitajaid. "Isegi metsaregistri avalik osa on vahendajatele piisavalt huviväärne. Hiljuti muutis riik kaardil nähtavaks ka kõik need metsaeraldised, millel tohib teha uuendusraiet ehk lageraiet. Just sellised tükid tõotavad iseäranis suurt tulu vahendajatele ja metsa ülestöötajatele." (Niitra, 2017) Süsteemi kõige nõrgemaks lüliks on sellega seotud inimesed. Kasuahnus on väga levinud rünnaku motiiv. Ebaseaduslikult saadud andmed võivad anda ettevõttele konkurentide ees ebaseadusliku ja ebaeetilise eelise. Kõneluse töötaja elukaaslane töötab ühes riigi suurimas metsavahendusfirmas metsahindajana. Eelnev taustakontroll oleks võinud tuvastada töötaja puhul huvide konflikti ja talle poleks pidanud selliseid õiguseid andma või oleks vähemalt tulnud võtta selle töötaja tegevus teravdatud tähelepanu alla. Taustakontrolli vajaduse kehtestamine oleks organisatsiooniline tugevdusmeede. Selle tulemuste alusel juurdepääsu piiramine oleks tehniline tõkestusmeede. Selliste juhtumite uurimisega tegeleb Andmekaitse Inspektsioon. Ilmselt polnud metsaregistri puhul kasutatud tollel ajal kehtinud Infosüsteemide Turvameetmete Süsteemi ISKE. 10.06.2022 ilmus Postimehes artikkel selle kohta, et keskkonnaseadustikus ja metsaseaduses jõustusid muudatused, mis peaksid tulevikus selliste probleemide tekkimist vähendama. Muudatused piiravad agressiivsete ja tüütute metsa ülesostjate, keda kutsutakse kährikuteks, juurdepääsu metsaandmetele. Uue korra kohaselt ei ole füüsilisest isikust metsaomanike metsa tagavara ja raiemaht avalik info samas kui juriidilisest isikust metsaomanike sellekohane info on. Juhul kui metsaregistrisse kantud andmed metsa kohta annavad infot isiku vara ja majandusotsuste ning majandusliku käitumise kohta, siis loetakse need andmed isikuandmeteks. Sellistele isikuandmetele avaliku juurdepääsu andmine kahjustab eraelu puutumatust. Artikkel märgib, et seaduseparandused tõid metsaseadusesse õigusselguse. ## Küsimus: Kust saaks rohkem teada paindmetoodikatest? **Vastus:** Soovitan vaadata seda Bertrand Meyeri ettekannet (osa 1 ja osa 2), mis põhineb tema uuel raamatul. Raamat ise on olemas Tallinna Tehnikaülikooli raamatukogus. Tallinna Tehnikaülikooli raamatukogu kaudu on tehtud üliõpilastele elektrooniliselt kättesaadavaks raamat Disciplined Agile Delivery: A Practitioner’s Guide to Agile Software Delivery in the Enterprise. See kirjeldab suurte projektide jaoks kohandatud paindmetoodikat.Kuidas kasutada O'Reilly digitaalset platvormi? Selles magistritöös valitakse suurettevõttele sobivat skaleeritavat paindmetoodikat. Töös antakse põhjalik ülevaade järgmistest metoodikatest: Scaled Agile Framework (SAFe), Nexus, Disciplined Agile Delivery (DAD), Large-Scale Scrum (LeSS) ja Large-Scale Scrum Huge (LeSS Huge). ## Küsimus: Mida saavad inimesed ise ära teha oma andmete ja privaatsuse kaitsmiseks? **Vastus:** Olla tähelepanelikud! Näiteks isikuandmete kaitse seaduse kohaselt kuuluvad andmed tervisliku seisundi kohta eriliiki isikuandmete hulka, mille töötlemisele on ranged nõuded. Tänapäeva nutiseadmete ja enese-eksponeerimise ajastul lekitavad paljud inimesed teadmatusest või hoolimatusest enda sellekohaseid andmeid osapooltele, kelle puhul pole võimalik kontrollida, kes ja mida nende andmetega teeb. Nendeks andmeteks on kantavate seadmete poolt kogutud tervisenäitajad, mis edastatakse teenusepakkujale, kes omakorda võimaldab vaadata nende andmete kohta aruandeid või pakub soovitusi. Tsitaat artiklist "Andmekaitse Inspektsioon töötas välja uue juhise «Kantavad seadmed ja privaatsus», milles selgitatakse kantavate seadmete (wearable computing) olemust ja nende kasutamise mõju inimese eraelule. Samuti jagatakse juhises soovitusi kasutajate privaatsuse paremaks tagamiseks." ## Küsimus: Millised Eesti riiklikud infosüsteemid töötlevad delikaatseid isikuandmeid? **Vastus:** Uus isikuandmete kaitse seaduse redaktsioon, mis võtab üle Euroopa Liidu isikuandmete kaitse üldmääruse, ei kasuta terminit "delikaatsed isikuandmed". Kuid seal on juttu "eriliigilistest isikuandmetest". Eriliiki isikuandmete alla kuuluvad enamus selliseid andmeid, mis varasema sõnastuse järgi olid Eestis käsitletavad kui delikaatsed isikuandmed ("Eriliiki isikuandmed on andmed, millest ilmneb rassiline või etniline päritolu, poliitilised vaated, usulised või filosoofilised veendumused või ametiühingusse kuulumine, geneetilised andmed, isiku kordumatuks tuvastamiseks kasutatavad biomeetrilised andmed, terviseandmed ja andmeid seksuaalelu ja seksuaalse sättumuse kohta.")Riigi infosüsteemi haldussüsteemist RIHA on võimalik vaadata, millised riigi registrid sisaldavad milliseid delikaatseid isikuandmeid. Valige "RIHA kataloog => Otsi andmeobjektidest". "Täpsusta otsingut" võimaldab otsingut täpsustada. Otsingu tulemuses on veerg "Isikuandmed", mis näitab, kas tegemist on isikuandmetega ning kas need on eriliigilised isikuandmed. Siin on näitena otsingutulemus selle kohta, millistes infosüsteemides salvestatakse eriliigilisi isikuandmeid. ## Küsimus: Milliseid andmebaaside kursustes käsitletud teemasid puudutavaid järeldusi saab teha 2017. aasta suvel nurjunuks kuulutatud pensionide ja sotsiaaltoetuste maksmise infosüsteemi uue versiooni SKAIS2 arendusprojekti alusel? **Vastus:** Väga sageli ei tea süsteemi tulevased kasutajad ja selle arenduse eest maksjad (ei pruugi olla üks ja sama isikute ring), milline täpselt peaks uus süsteem olema. Tulemuseks võivad olla lepingud, mida on ebareaalne täita. Sõltub tellija poolsete läbirääkijate tarkusest, kas nad suudavad lepingusse suruda piisavad hilinemisest tulenevad sanktsioonid ja sellega motiveerida ka arendajaid andma realistlikke lubadusi. Nagu ütleb Marek Helm, siis tellija peab olema tark. Tarka tellijat ei saa ebareaalsete lubadustega petta. Lehmani tarkvara evolutsiooni seadused (vt "Andmebaasid I", teema 1) ütlevad, et tarkvara funktsionaalsus ja keerukus ajas suureneb ning mingil hetkel jõutakse punkti, kus lihtsam on olemasoleva süsteemi edasise muutmise asemel see nullist uuesti kirjutada e puhtalt lehelt alustada. Samasse seisu jõuti sotsiaalkaitseameti infosüsteemiga SKAIS, mille puhul selgus 2013. aastaks, et olemasolev tarkvara uut töövõimereformi toetada ei suuda ning tuleb alusada selle tarkvara uue versiooni SKAIS2 loomisega. Suuri süsteeme tuleks arendada väiksemate alamprojektide või äriliselt loogiliste osade (nt ühe teenuse) kaupa. Seda näeb ette strateegilise analüüsi metoodika (vt "Andmebaasid 1", teema 7). Seda soovitab tarkvaraettevõtte Helmes arendusjuht Raul Ennus (siin) ja tarkvaraettevõtte Thorgate tehnoloogiajuht Virgo Riispapp (siin). Sellest saadi lõpuks aru ka SKAIS2 arendamise juures – kui algselt sõlmiti leping terviksüsteemi arendamiseks, siis 2017. aastal, enne arendajaga lepingu katkestamist, mindi üle osade kaupa arendusele. Samuti kirjutab Aivar Pau, et SKAIS2 arendamise uue hanke puhul jagatakse see tükkideks, kusjuures iga arendusetapp puudutab ühte teenust. Selleks tükeldatakse ka kogu süsteemi arhitektuur osadeks nagu üldkasutatavad komponendid, integratsioonikiht, ärifunktsionaalsused, arveldusmoodul ja kasutajaliidesed. Aivar Pau kohaselt sellist tükeldust varem ei tehtud. Süsteemi tükeldamist alamosadeks ja alamosade arendamise jaoks eraldi projektide algatamist näeb samuti ette strateegiline analüüs (vt Andmebaasid I, teema 7). Sellise väiksemate osade kaupa arendamise korral võivad süsteemi erinevate osadega töötada erinevad arendusfirmad. Süsteem ei valmi mitte korraga (suure pauguga), vaid osade kaupa. Väiksematest osadest nagu Lego klotsidest kokkupandud süsteemi korral on lihtsam ja odavam üksikuid osi parandada ja välja vahetada.  Tarkvara arhitektuur on oluline ja aitab tagada, et see klotsidest moodustis oma raskuse all kokku ei kuku. Suurte projektide korral on hea mõte lasta arendajatel teha proovitöö ning arvestada hanke võitja valimisel ka muude kriteeriumitega kui kõige madalam hind. Projekti prioriteetide kolmnurk (vt "Andmebaasid I", teema 7) ütleb, et kui eesmärgiks on madal hind ja kiire valmimine (nagu SKAIS2 puhul alguses see oli), siis ei saa tulemus olla kõrge kvaliteediga. Muide, sellist valikut, kus saab saavutada vaid maksimaalselt kaks eesmärki kolmest tuntakse trilemmana. Riiklikus sotsiaalvaldkonnas, kus kõikvõimalikud reeglid ja maksete suurused sõltuvad poliitikute suvast, on nõudmised äärmiselt muutlikud. See sai SKAIS2 arendamisele lõpuks saatuslikuks. Selliste süsteemide arendamisel tuleks kindlasti kasutada iteratiivset arendust (vt "Andmebaasid II", teema 1). Sama soovitab ka Helmese arendusjuht Raul Ennus (siin). Arvestades nõudmiste muutlikust tuleks luua tarkvara, mida kasutajad saavad uute reeglite kehtima hakkamisel ise kohandada e konfigureerida, mitte ei pea kogu aeg tellima arendajatelt uusi arendustöid. Sellised süsteemid võivad olla andmetega juhitavad (vt "Andmebaasid II", teema 1). Samas tuleb ette vaadata, et paindlikuse tagaajamisega üle ei pingutata ning ei lisata sellega süsteemi asjatut keerukust. Tarkvara peaks olema hästi evolutsioneeritav. Samas  seda soodustav lähenemine, mille kohaselt on süsteemi igal alamosal (teenusel/mikroteenusel) oma andmebaas (rakenduse andmebaas), mille vahel võib ka olla andmete dubleerimine, ei ole hästi kooskõlas riiklike infosüsteemide nõuete ja vajadustega. Arendusse tuleks võimalikult varakult kaasata süsteemi lõppkasutajaid ja hakata neile tagasiside saamiseks iteratiivselt süsteemi uusi versioone esitlema. Kasutajad saavad anda tagasisidet nii süsteemi kasutatavuse kui ka funktsionaalsuse kohta. Suurte riiklike süsteemide puhul võib kasutada fookusgruppe. SKAIS2 puhul tuleks kaasata nii igapäevaseid makseid tegevaid ametnikke kui ka maksete saajaid. Oluline on võimalikult varakult ja regulaarselt saada lõppkasutajate tagasisidet, tagamaks, et uues süsteemis oleks neile kõik lihtne ja mugav. Seda ütlevad nii TransferWise'i arendusjuht Alvar Lumberg (siin) kui Helmese arendusjuht Raul Ennus (siin). Selle asemel, et iga allüksus (riigi puhul näiteks ministeerium) põlve otsas oma süsteemi arendaks, võiks luua ühissüsteeme üle erinevate allüksuste haldusalade. Sellisel viisil on ka tellijate ja juhtide summaarne ajupotensiaal suurem ja ehk tuleb paremini välja. Riik viib sarnase põhjendusega läbi haldusreformi – väikesed haldusüksused jäävad igasuguste suurte projektidega üksi hätta, vaja on jõud ühendada. ## Küsimus: Mis on andmesaatkonnad? **Vastus:** Juhin Teie tähelepanu uudisele andmesaatkondade kohta, mis seostub nii teemaga 5 (andmete turvalisus) kui ka 12 (hajusad andmebaasid). Tegemist on näitega, kuidas liiasust kasutatakse andmete kaitse ühe vahendina. Pange tähele, kuidas artiklis rõhutatakse korduvalt andmete tervikluse vajadust "Selle kontseptsiooni juures ei saa me aga üle ega ümber vajadusest andmete tervikluse järele –kuidas me tagame, et mingi Eestis kasutusel olevas andmekogus ja selle peegelduses kas siis saatkondades ja mujal välismaa pilveteenustes olevad andmed oleksid igal ajahetkel samad." Teemas 12 on juttu CAP teoreemist, mille kohaselt andmete hajutatud paiknemise korral on disaineritel valida, kas tagada süsteemi kättesaadavus igal ajahetkel (leppides sellega, et andmed koopiates pole igal hetkel ühesugused) või koopiate kooskõla igal ajahetkel e terviklus (leppides sellega, et süsteemi või selle osi ei saa mõnikord kasutada). Paljud (kergekaalulisemad) hajutatult paiknevad süsteemid eelistavad tagada kättesaadavust. Kriitilise tähtsusega andmetega süsteemid (nagu riiklikud süsteemid, aga ka pangad), aga ei saa kuidagi koopiate kooskõlast (terviklusest) mööda vaadata. 2019. aasta uudise kohaselt on Eesti esimesed andmekogud Luksemburgis asuvasse andmesaatkonda talletanud. Esimestena kanti sinna üle e-toimiku, kinnistusraamatu, äriregistri ning Riigi Teataja andmebaasid. 2019. aasta jooksul oli riigil kavas varundada veel kümme kõige kriitilisemat andmekogu. **Märksõnad:** andmesaatkond ## Küsimus: Tooge palun näiteid suurandmetest (big data). **Vastus:** Uudis andmete olulisuse kohta, mis kirjeldab ühte võimalikku tulevikku. Autode sensorite abil kogutavad andmed kuuluvad suurandmete kategooriasse. Kokkuvõtteks võib öelda, et suurandmeid iseloomustamiseks kasutatakse järgnevaid kriteeriume. Volume – koguhulk on suur. Velocity – uute saabuvate andmete hulk on suur – andmeid tulvab nagu kosest juurde ja nende põhjal on vaja kohe midagi järeldada. Näiteks ennustuste kohaselt oli 2020. aastal arvutisüsteemides loodavate andmete hulk 44 korda suurem kui 2009. aastal. Variety – andmestruktuuride varieeruvus on suur – erinevad formaadid, muutuv struktuur. **Märksõnad:** suurandmed --- # Teema: Iseseisva töö projekt ## Küsimus: Kas "Andmebaasid II" iseseisvas töös võib rakenduse tegemisel kasutada mõnda ORM (Object-Relational Mappers, objekt-relatsioonvastenduse) vahendit. **Vastus:** See pole keelatud, eeldusel, et loodud rakendus kasutab andmebaasi läbi avaliku andmebaasi liidese e virtuaalse andmete kihi. Teiste sõnadega peaks rakendus lugema andmeid vaadetest (näiteks Djangos on see võimalik) ning muutma andmeid kasutades andmebaasiserveris talletatud rutiine (näiteks Djangos on see võimalik). Andmete kitsendustele vastavuse kontroll peab toimuma andmebaasi tasemel (kasutades deklaratiivseid kitsendusi ja reegleid), mitte rakenduse tasemel nagu ORM vahendid üldiselt propageerivad. Rakenduse tasemele andmete kontrolli probleemiks on: üleliigsed päringud andmebaasi põhjal, mis kokkuvõttes aeglustavad ORM abil loodud programmi tööd, kontrollide ebapiisavus selles mõttes, et juhul kui samu andmeid kasutab samaaegselt mitu kasutajat, siis võivad need kontrollid lasta läbi reeglitele mittevastavaid andmeid. ORM vahendi(te) probleemidele osutab see uuring 67 avatud lähtekoodiga tarkvara põhjal. Siin on veel üks suure hulga põhjendustega selgitus, miks üks arendaja loobus ORMi kasutamisest ning eelistab ise SQL lauseid kirjutada. Siin on arutelu, kus kõrvutatakse ORMi ja andmebaasiserveris talletatud rutiinidest, vaadetest ja hetktõmmistest koosneva virtuaalse andmete kihi kasutamist. Kuigi eelnev näitab, et ORMi ja andmebaasi avalikku liidest saab koos kasutada, siis praktikas on need alternatiivid. Alternatiiv 1: Rakendus kasutab andmebaasi läbi ORMi. ORM vahend genereerib ise SQL koodi, millega loetakse ja muudetakse andmebaasis andmeid otse baastabelites. Selleks, et piirata kasutajate juurdepääsu teatud tingimustega tabeli ridadele, pakuvad andmebaasisüsteemid vahendeid nagu turvapoliitikad (PostgreSQL) või peeneteralised juurdepääsupiirangud. Alternatiiv 2: Rakendus kasutab andmebaasi läbi avaliku andmebaasi liidese, mille realiseerimiseks kasutatakse andmebaasis loodud vaateid, rutiine ja materialiseeritud vaateid e hetktõmmiseid. Rakendus ei pöördu otse baastabelite poole, vaid kasutab nendes olevaid andmeid läbi avaliku liidese. **Märksõnad:** rutiin, funktsioon, protseduur, hetktõmmis, materialiseeritud vaade, virtuaalne andmete kiht, andmebaasi avalik liides ## Küsimus: Kas "Andmebaasid II" projekti tegemisel tuleb tagada kooskõla "Andmebaasid I" projekti mudelitega? **Vastus:** Jah tuleb. Mudel on reaalsuse lihtsustatud esitus. Olen seisukohal, et mudelite koostamisel tuleb südamest ja järjekindlalt teha seda esitust võimalikult täpselt. Kui süsteemi arendamise käigus tekib juurde uusi nõudmisi, siis tuleb üritada mudelit ja realisatsiooni kooskõlas hoida. Muidu tekib olukord, et keegi uurib heauskselt seda mudelit, kulutab selle juures aega, aga siis saab teada, et TEGELIKULT käivad asjad hoopis teisiti. See mudel, see oli lihtsalt üks vanaks läinud joonistus/tekstimass, mida poleks tasunud üldse vaadatagi. AEG on midagi, mida mingi rahaga tagasi/juurde osta ei õnnestu. Kui eesmärgiks oli saada aru praeguse süsteemi versiooni toimimisest, siis kahjuks sellise mudeli vaatamiseks kulunud aeg oli kaotatud aeg. Leian, et kui ei suudeta tagada mudeli ja realisatsiooni kooskõla, siis ei tohiks mudelit presenteerida olemasoleva süsteemi kirjeldusena. Sellised mudelid tuleks säilitada selge märkega - ajalooline mudel. "Andmebaasid II" projekt ei näe ette ajalooliste mudelite esitamist. Töö suhteliselt väikest mahtu arvestades oodatakse projektide autoritelt tarkvara ja mudelite kooskõla tagamist. Kui "Andmebaasid I" projekt on tehtud töövihiku põhjal (siia alla kuuluvad ka projektita üliõpilastele välja pandud kolm projekti), siis tuleb andmebaasis realiseerida kõik need kitsendused, mida kontseptuaalne andmemudel ette näeb - kitsenduste kontseptuaalsest andmemudelist eemaldamine ei ole lubatud. Kitsendusi kontseptuaalsesse andmemudelisse ja sealtkaudu ka andmebaasi juurde lisada on lubatud! ## Küsimus: Kas igal ühel peab olema oma ligipääs serverile, isegi kui töötame ühe andmebaasiga projektis? **Vastus:** Jah, igaüks peab sisse logima oma kontoga, igaühele loon eraldi konto, igaüks peab seda mult eraldi kirjaga küsima. PostgreSQLi puhul on serveris Teile antud ülikasutaja (superuser) õigused, st pääsete piiranguteta ligi kõikide teiste üliõpilaste tööle. ## Küsimus: Kas iseseisva töö jõuab valmis ainult praktikumides tööd tehes? **Vastus:** Arvan, et ei jõua. Hindan, et kui praktikumides tõhusalt töötada, siis võiks valmis jõuda 50-75% protsenti projektist (väga palju sõltub ka tegijatest). Kindlasti aitab praktikumides tegemise kiirust ja kvaliteeti parandada see, kui olete juba enne praktikumi algust lugenud samm-sammulise juhendi ülesannet ning kodulehele pandud seda toetavaid materjale. Kui teete praktikumis tööd ja siis kaotate tehtud töö ära (pole versioonihaldust), siis ei pruugi muidugi ka nii palju valmis saada. Seega olge palun hoolsad! ## Küsimus: Kas iseseisva töö tegemisel on võimalik seda automaatselt kontrollida ja saada seega töö kohta jooksvalt tagasisidet? **Vastus:** NB! Järgnevalt nimetatud kontrollpäringute käivitamise veebilehtedele saab ligi nii Tehnikaülikooli kui ka Eesti IP ruumist. Kui keegi peaks vajama ka välisriikidest ligipääsu, siis eelnevalt tuleb luua FortiClient VPN ühendus.Jah on. Teie töö hindamiseks kasutatakse automatiseeritud disaini kontrollimise vahendit (erinev tarkvara PostgreSQL ja Oracle jaoks, kuid need lähtuvad samast põhimõttest). Teil on võimalus jooksvalt ise oma andmebaasi selle abil analüüsida. Eeldus on, et andmebaas on apex2.ttu.ee serveris (PostgreSQL) või apex.ttu.ee serveris (Oracle) (see on muide projekti reeglitega nõutud).Vaadake selle kohta videot. Vahend käivitab andmebaasi süsteemikataloogi põhjal päringuid. Osa päringuid suudavad leida vigu. Osa aga otsivad andmebaasi disainist halva lõhnaga kohti (vt halvasti lõhnav disain ja halvasti lõhnav kood). Halvasti lõhnavad kohad ei takista andmebaasi ja seda kasutavate süsteemide toimimist, kuid muudavad andmebaasi kasutamise, haldamise või arendamise mingis aspektis raskemaks kui see võiks olla. Halvasti lõhnavad kohad on sügavamate probleemide sümptomid. Nende probleemide lahendamine aitab koodi/mudelit/disaini/arhitektuuri puhastada. Halb lõhn on tehnilise võla tunnus. Tehniline võlg tähendab, et "asi" töötab, kuid saaks olla sisemiselt tehtud paremini. Kuna praegu on seal midagi "üle jala" lastud, siis see on probleem tulevikus, kui "asja" on vaja edasi arendada. Kliendile kiiresti töötava asja üleandmiseks on võetud võlga tuleviku arenduste arvelt. Tehnilist võlga aitab vähendada refaktoreerimine. Vahend on mõeldud andmebaasi osaliseks staatiliseks versifitseerimiseks – kontrollimiseks, kas andmebaas vastab tehnilistele nõuetele. Vahendi kasutamine aitab vastata küsimusele: Kas andmebaasi tehakse õigesti? Staatiline tähendab, et kontrollimiseks vaadeldakse andmebaasi struktuuri ja käitumise kirjeldust, mitte ei viida andmebaasi põhjal läbi tegevusi (see oleks dünaamiline verifitseerimine). Verifitseerimine ei ole sama mis valideerimine. Andmebaasi valideerimine peab vastama küsimusele: Kas andmebaas võimaldab hoida kõiki neid andmeid, mida kasutajal on vaja hoida (st kas vastab kasutajate nõudmistele, kas teeme õiget andmebaasi)? Kontroll, kas andmebaasi disaini mudel realiseerib andmebaasi vastavalt kontseptuaalses andmemudelis esitatud nõuetele, läheb valideerimise alla. Probleem on, et need nõuded võivad olla vananenud või valesti kirja pandud. Andmebaasi valideerimine annab vastuse, kas andmebaas ka tegelikult nõudeid täidab.Võite neid päringuid regulaarselt ise käivitada ja interpreteerida üritada. Küsimuste korral pöörduge õppejõu poole. Oleks väga hea, kui mõnes semestri lõpu praktikumis, kui projekt juba valmis saama hakkab, jõuaksite koos õppejõuga need päringu tulemused üle vaadata. Praktikas ongi semestri teise poole praktikumid suures osas pühendatud üliõpilastega koos nende andmebaasi põhjal käivitatud päringute ülevaatamisele.PostgreSQLKui teete oma projekti PostgreSQLis, siis minge aadressile. Logige sisse kasutades apexi kasutajanime ja parooli. Valige kontrollitav andmebaas. Ilmselt on see samasuguse nimega nagu ühe projekti tegija kasutajanimi ja sisaldab tema matriklinumbrit. Valige test "Databases II (fall 2022)". Vaadake päringu tulemusi, milles on üks või rohkem rida. Selleks, et tulemuses oleksid vaid päringud, mis tagastavad vähemalt ühe rea, vajutage nupule "Execute and show only queries that return rows". Iga päringu korral lugege kirjeldust, vaadake tulemusi. Kui päringute käivitamisel on valitud "Generate SQL statements to fix problems", siis väljastab programm mõningate probleemide puhul nende lahendamiseks mõeldud SQL lauseid. Päringuid on erinevat tüüpi. General (üldine): päringud, mis otsivad andmebaasist spetsiifilist infot, kuid otsuse selle kohta, kas midagi on õigesti või valesti peab tegema inimkasutaja, kes tulemust vaatab. Flaw detection (probleemide otsimine): päringud, mille tulemuses olev iga rida osundab mingile võimalikule disaini probleemile/veale. Siiski on võimalikud vale-positiivsed ja vale-negatiivsed tulemused. Siin on näited mõnedest PostgreSQLi andmebaasi disaini probleemidest. Kataloogis on esitatud palju rohkem probleeme ja nende esinemist tuvastavaid päringuid. Software measure (tarkvara mõõdik): päringud, mis arvutavad andmebaasi skeemi põhjal mingi arvulise väärtuse. Usaldusväärsus on hinnang sellele, kuidas päring oma eesmärke täidab. Keskkonnas on mitmeid teste. Testi "Quick test" alla on koondatud probleemide otsimise päringud, mille puhul tulemuses olev iga rida viitab suure tõenäosusega sellele, et andmebaasi disainis on probleem/viga.PostgreSQL jaoks koostatud päringud on avatud lähtekoodiga ja on avaldatud otsimist võimaldavas kataloogis, mille viide on projekti kodulehel SIIN.Oracle Kui teete oma projekti Oracles, siis minge aadressile. 990999 tuleb asendada matrikli numbriga, mida kasutate projekti tulemusena loodud andmebaasiobjektide nimedes. Oraclele on loodud palju vähem kontrolle kui PostgreSQLile (üks põhjus, miks eelistada iseseisva töö andmebaasisüsteemina PostgreSQLi) ning Oracle kontrollpäringute täitmine võtab PALJU rohkem aega kui PostgreSQL päringute täitmine. **Märksõnad:** automaatkontroll, kontrollpäring, kontrollpäringud, queries2 ## Küsimus: Kas iseseisva töö ülesande lahendamise järel on võimalik automaatselt üle vaadata just selle ülesande tulemust? **Vastus:** Jah, PostgreSQL puhul on see osade ülesannete puhul võimalik. Minge: http://apex2.ttu.ee/queries2 Valige kontrollitav andmebaas.Seejärel valige testi asemel kategooria. Kategooria all on koos nii päringud, mis otsivad vigu kui ka päringud, mille tulemus annab ülevaate.Nimetan järgnevalt kategooriad, mida mingi ülesande puhul valida. Ülesanded 2-4 (baastabelid, kitsendused, indeksid) CHECK constraints, Compensating actions, Data types, Default value, Fatal problems, Missing data, Naming, Performance, Regular expressions, Relationships between tables, Structure of base tables, Uniqueness. Ülesanne 5 (välised tabelid, testandmed) Distributed database, Data at the database logical level. Ülesanne 6 (domeenid) Domains Ülesanne 7 (vaated) Derived tables Ülesanne 8 (rutiinid) User-defined routines Ülesanne 11 (trigerid) Triggers and rules Ülesanne 12 (õigused) Security ## Küsimus: Kas lävendi ületanud projekti saab parandada? **Vastus:** Lävendi ületanud projekti parandada ei saa. Kogu protsess oli organiseeritud nii, et parandamine toimus enne esitamist. Suuremas osas praktikumidest toimub iseseisva töö projekti tegemine. Selle käigus peaks olema piisavalt võimalusi tehtud tööle jooksvalt tagasiside saamiseks. Kui soovite uusi punkte, siis tuleb teha uus projekt uuel teemal. ## Küsimus: Kas ma võin "Andmebaasid II" projektis realiseerida teise töökoha kui "Andmebaasid I" projektis? **Vastus:** Jah võite, kuid see ei ole mingil juhul kohustuslik. Ka "Andmebaasid II" kehtib reegel, et realiseeritaval töökohal peab toimuma nii andmete lugemist kui ka andmete muutmist. Kui tegite "Andmebaasid I" projekti töövihiku järgi ning realiseerisite juhataja töökoha, siis loomulikult võite soovi korral realiseerida (funktsionaalsuselt mahukama) X halduri töökoha, kuid mahuliselt on piisav ka juhataja töökoht. NB! Sellel lehel välja pakutud "Andmebaasid I" projektid on samuti töövihiku järgi tehtud. Aine projekt on sisuliselt migreerimise projekt koos koodi puhastamisega. Töö käigus on vaja süsteem viia üle ühelt platvormilt teisele. On loogiline, et rakenduses realiseeritav töökoht jääb samaks. Realiseeritav töökoht võib seada piiranguid rakenduse tegemiseks kasutatavale vahendile. Üldpõhimõte on, et "Andmebaasid II" aines realiseeritav arhitektuuriline lahendus (kahekihilne klient-server süsteem, kus rakendus on kasutaja arvutis vs n kihiline (n>2) veebipõhine süsteem) peab sobima ka pärisellu. Süsteemi sisemiste pädevusalade puhul sobib nii kasutaja arvutis olev rakendus kui veebirakendus. Välised pädevusalad (kõikvõimalikud kliendid ja partnerid) vajavad veebirakendust. **Märksõnad:** iseseisev töö, projekt, migreerimine ## Küsimus: Kuidas esitada iseseisev töö? **Vastus:** Iseseisva töö esitamiseks (sõltumata sellest, kas tegemist on lõplikult valmis versiooniga või vaheversiooniga, millele soovite konsultatsiooni käigus tagasisidet) valige õppekeskkonna vasakpoolsest menüüst Kiirvalik=> Vastamine ning avanenud leheküljelt ülesanne "Iseseiseva töö esitamine". Ülesande vastusena saab saata ka faile. Ülesandele esmakordselt vastamine.Vajutage ülesande juures lingile "saada faile". Avanenud aknas on iga küsimuse juures link "Saada fail". Sellele vajutades tekib lehe ülaosas võimalus faili valimiseks. Faili serverile saatmiseks tuleb vajutada nupule "Saada ära".Ülesande vastuse parandamine.Vajutage ülesande juures lingile "paranda/muuda". Avanenud lehel saab kustutada küsimustega seotud faile ja lisada uusi faile.NB! Proovige kontrolli eesmärgil enda üleslaetud faile alla laadida! Kui faili suurus on 0 KB (üleslaadimine ilmselt ebaõnnestus), siis on faili suurus punasega tähistatud.NB! Nupule "Salvesta muutused vastuse tekstis" tuleb vajutada vaid siis, kui lisaks failidele kirjutasite midagi ka küsimuste vastuste lahtritesse. NB! Iseseisva töö lõpliku versiooni esitamisel peab vastuse saatma üks projekti liige. ## Küsimus: Kuidas kirjeldada kujundlikult (metafoore kasutades) õppeaine aineprojekti sisu? **Vastus:** Tehnilist terminoloogiat kasutades tähendab aineprojekt süsteemi (andmebaasi ja rakenduse) migreerimist uuele platvormile ning selle käigus andmebaasi/rakenduse/mudelite refaktoreerimist. Andmebaas tuleb realiseerida uues andmebaasisüsteemis ning rakendus (mille tegemise vahendi valik on vaba) tuleb panna seda andmebaasi kasutama. Andmebaasi ja rakenduse skoop võrreldes lähteprojektiga ei muutu (välja arvatud see, et tuleb realiseerida ka kasutusjuht "Tuvasta kasutaja", mis lähtesüsteemis on ilmselt tegemata). Kujutage andmebaasisüsteemi ette restoranina. Iga restoran pakub külastajale oma menüüd (näiteks andmetüüpe ja andmebaasi programmeerimise võimalusi), kuid selles on ka omad kiiksud ja piirangud (näiteks klient ei saa ilma tellimata pikalt istuma jääda või et lemmikloomaga sisse ei lubata). Samuti on restorani külalistel oma kindlad eelistused (näiteks taimetoit), mis on antud juhul kirja pandud kontseptuaalsesse andmemudelisse. Sisuliselt on Teie ülesanne minna uude (paremasse, kallimasse) restorani ning arvestades enda soovide ja piirangutega ning restoranis pakutavaga teha restoranis tellimus ja lasta see ära täita (lauda tuua). **Märksõnad:** metafoor, näide, iseseisev töö, projekt, andmebaasisüsteem, restoran ## Küsimus: Kuidas PostgreSQLis tehtud iseseisva töö andmebaasi kiiresti iseseisvalt kontrollida? **Vastus:** NB! Järgnevalt nimetatud kontrollpäringute käivitamise veebilehtedele saab ligi nii Tehnikaülikooli kui ka Eesti IP ruumist. Kui keegi peaks vajama ka välisriikidest ligipääsu, siis eelnevalt tuleb luua FortiClient VPN ühendus.Kui teete projekti PostgreSQLis, siis saate oma andmebaasi testimiseks tarvitada kiirtesti, kuhu on koondatud kontrollid, mille tulemused osutavad suure tõenäosusega probleemile/veale. Tähelepanu! Kui kiirtest midagi ei leia, siis see ei garanteeri probleemide/vigade puudumist. Samuti võib kiirtesti tulemuses olla nii väärpositiivseid kui väärnegatiivseid tulemusi. Kiirtesti käivitamiseks minge andmebaaside disaini kontrollimise rakendusse (vanem kasutajaliides). Valige huvipakkuv andmebaas. Testiks valige Quick test. Andke korraldus test käivitada. Vanemas kasutajaliideses vajutage selleks nupule "Execute and show only queries that return rows". Stiilinäiteks on päring, mis loendab kokku andmebaasis kasutaja poolt loodud trigereid ja reegleid. Tulemuses on rida vaid siis, kui nende arv on alla kolme. WITH activedb AS (SELECT trigger_schema, trigger_name, 'TRIGGER' AS type FROM INFORMATION_SCHEMA.triggers WHERE trigger_schema NOT IN (SELECT schema_name FROM INFORMATION_SCHEMA.schemata WHERE schema_name<>'public' AND schema_owner='postgres' AND schema_name IS NOT NULL) UNION SELECT r.schemaname, r.rulename, 'RULE' AS type FROM pg_catalog.pg_rules r, pg_catalog.pg_namespace n, pg_catalog.pg_user u WHERE r.schemaname = n.nspname AND n.nspowner = u.usesysid AND (n.nspname = 'public' OR u.usename <> 'postgres')) SELECT 'Too few triggers and/or rules, must be at least 3' As comment, (SELECT Count(*) AS cnt FROM activedb) AS cnt WHERE (SELECT Count(*) AS cnt FROM activedb)<3; Mõned kommentaarid. Skeemis pg_catalog on PostgreSQL süsteemikataloogi baastabelid. Skeemis INFORMATION_SCHEMA on süsteemikataloogi baastabelite põhjal defineeritud standardse struktuuriga vaated. Trigerite ja reeglite otsimisel on vaja jätta välja süstemikataloogis loodud trigerid ja reeglid. WITH klausel võimaldab defineerida käesoleva lause piires kasutatavaid virtuaalsed tabelid, millele lauses saab peale defineerimist nime kasutades viidata. See võimaldab SQL koodi paremini struktureerida. WITH klauslis võib olla järjest mitu alampäringut. Igas sellises alampäringus saab viidata kõikidele selles lauses eespool defineeritud alampäringutele. PostgreSQLis võib kirjutada SELECT lause, kus puudub FROM klausel, aga on WHERE klausel. WHERE klausli eesmärgiks on antud juhul tagada, et päringu tulemuses on rida vaid siis, kui trigerite ja reeglite koguarv on alla kolme. SELECT klauslisse saab kirjutada konstante ja ka mittekorreleeruvaid skalaarseid alampäringuid. Nende väärtuseid korratakse kõikides päringu tulemuseks olevates ridades. Väikeste andmehulkade korral ei ole PostgreSQLis NOT IN konstruktsiooni kasutamine probleem, kuid suurte andmehulkade korral tuleks sellest töökiiruse huvides hoiduda. **Märksõnad:** automaatkontroll, kontrollpäring, kontrollpäringud ## Küsimus: Kuidas realiseerida see, et põhiobjekti X (nt Auto või Kaup) eksemplari andmete muutmine on võimalik vaid siis, kus see eksemplar on mingis kindlas seisundis? **Vastus:** Kui loote rutiini X andmete muutmiseks, siis kirjutage see kontroll sisse rutiinis sisalduvatesse lausetesse. Näiteks oletame, et kauba andmeid saab muuta (v.a. seisundi muutmine) vaid siis, kui muudetav kaup on seisundis ootel või mitteaktiivne. Oletame, et ootel seisund on koodiga 1 ja mitteaktiivne seisund on koodiga 3. Rutiinis olevas UPDATE lauses oleks tingimusedUPDATE KaupSET ...WHERE kauba_kood=<etteantud kauba_kood>AND kauba_seisundi_liik_kood IN (1, 3)RETURNING kauba_kood;Kui näiteks kauba kategooria omamisi saaks kustutada vaid siis, kui kaup on kas seisundis ootel või mitteaktiivne, siis oleks kategooria omamise kustutamise rutiinis lauseDELETE FROM Kauba_kategooria_omamineWHERE kauba_kood=<etteantud kauba_kood>AND kauba_kategooria_kood=<etteantud kauba_kategooria_kood>AND EXISTS (SELECT * FROM KaupWHERE Kaup.kauba_kood=Kauba_kategooria_omamine.kauba_koodAND Kaup.kauba_seisundi_liik_kood IN (1, 3))RETURNING kauba_kood;Kui loote hiljem nende tingimuste kontrollimiseks trigerid, siis eemaldage need tingimused rutiinidest, et see kontrolli loogika poleks samas tarkvara kihis (andmebaas) dubleeritud. **Märksõnad:** andmebaasiserveris talletatud rutiin, funktsioon, protseduur ## Küsimus: Kuidas registreerida iseseisva töö projekti teema? **Vastus:** Tähtajaga 15. september 2023 tuleb registreerida iseseisva töö teema, rakenduses realiseeritav töökoht, esialgne kasutatavate vahendite valik ja üliõpilased, kes seda tööd üheskoos teevad. Kui otsustate hiljem teha midagi teisiti, kui vastuses kirjas, siis õppejõu teavitamiseks piisab ainult selle vastuse muutmisest. Iseseisva töö registreerimiseks valige õppekeskkonna vasakpoolsest menüüst Kiirvalik=> Vastamine ning avanenud leheküljelt ülesanne "Iseseiseva töö registreerimine". Ühte tööd võib teha koos kuni kolm inimest. Kui teete tööd mitmekesi, siis peab ülesandele vastama ainult üks tegijatest. Kui teete projekti üksinda, kuid otsite kaaslast, siis on võimalik seda soovi iseseisva töö teema registreerimisel väljendada. Nimetan järgnevalt ka mõningaid tüüpilisi probleeme vastustes ja loodan, et Te väldite neid. Teisi andmebaasisüsteeme peale PostgreSQL ja Oracle iseseisva töö tegemiseks kasutada ei saa (v.a töökohapõhise õppe projekt eelkokkuleppel õppejõuga). Oraclet ja MS Accessi on raske koos kasutada ja seega ei sobi MS Access Oracle andmebaasi rakenduse tegemiseks. Kui soovite teha andmebaasirakenduse MS Accessis, siis kirjutab see andmebaasisüsteemina ette PostgreSQLi. "Andmebaasid I" realiseeritud "Juhataja töökoht" on sobilik ning piisav realiseerimiseks ka "Andmebaasid II". Oracle Application Express vahendi abil ei saa (õigem oleks öelda, et "on väga tülikas") teha PostgreSQL andmebaasi kasutamiseks mõeldud veebirakendust. pgApex vahendi abil ei saa (õigem oleks öelda, et "on väga tülikas") teha Oracle andmebaasi kasutamiseks mõeldud veebirakendust. Enterprise Architect ja Rational Rose ei ole rakenduse tegemise vahendid, vaid on modelleerimisvahendid (CASE). ## Küsimus: Kuidas saada juurdepääs iseseisva töö tegemiseks mõeldud serverile? **Vastus:** Saamaks juurdepääsu aines vajaliku tarkvaraga serverile, tuleb täita esimene punkt praktikumi ülesandest nr 1. Seda juurdepääsu läheb vaja juba teises praktikumis. **Märksõnad:** server ## Küsimus: Kui projekti esimest korda hinnati ja see ei ületanud lävendit, siis kas peale parandamist projekti uuesti esitamisel saan hilinenud esitamise eest täiendavaid miinuspunkte? **Vastus:** Kõigepealt tahan rõhutada, et kursus on kavandatud selliselt, et projekti tegijal oleks võimalik saada korduvat ja põhjalikku tagasisidet juba ENNE esimest korda projekti esitamist. Enamik praktikume on pühendatud projekti tegemisele, andmebaasi disaini kontrolliks on automaattestimise võimalus ning sellest, mida üldse hinnatakse, annab ülevaate detailne hindamismudel. Loodetavasti tagab see, et projekt ületab lävendi esimesel korral ja suure varuga. Kui aga nii ei juhtu, siis on üliõpilasele pakkuda päästerõngas, millel on küll paraku hind. Kui iseseisev töö esitada peale parandamist teistkordselt, siis väheneb töö punktisumma kümne punkti võrra. Täiendavaid hilinemise miinuspunkte ei anta. Seega, kui projekti esmakordsel esitamisel sai see hilinemise eest viis miinuspunkti, siis neid punkte ei arvestata (st hilinemise/parandamise tõttu kaotab projekt kas viis või kümme punkti, mitte 5+10=15 punkti). Juhin tähelepanu, et hindamismudeli alusel saate seda kaotust kuhjaga kompenseerida, täites lisapunkte andvaid ülesandeid. Lisaks kaotate projekti uuesti esitamise vajaduse tõttu kõik praktikumides kogutud aktiivsuspunktid. Viimase põhjendus on, et kõik need punktid saadi praktikumides aktiivselt projektiga tegelemise eest. Tunnis kohapeal punkte kirja pannes on õppejõul raske hinnata, kas tegelemine oli aktiivne või näiline/vähetulemuslik. Kui tegelemine oli aktiivne, siis jõudis projekt kindlasti nii kaugele, et ületas esimese korraga lävendi. Kui tegelemine oli näiline/vähetulemuslik, siis võis tekkida projekti valmissaamisega probleeme ja lävend võis jääda esimesel katsel ületamata. Siis pole ka põhjust aktiivsuses eest punkte saada. ## Küsimus: Kui teeme iseseisva töö projekti, siis kas seda saab teha paralleeltööna (st projekti liikmed töötavad samaaegselt erinevate projekti osadega)? **Vastus:** Ülesandeid 2-4, mille tulemusena tuleb tehniliselt kavandada ja realiseerida andmebaasi baastabelid, niimoodi teha ei saa. Alates ülesandest 5, kui on vaja hakata tabeleid täiendama ning looma nendele pealisehitust (andmebaasi avalik liides, trigerid, rakendus), on see võimalik: nii ühe ülesande sees (näiteks erinevad üliõpilased lisavad testandmeid erinevatesse tabelitesse või loovad erinevaid vaateid) kui ka ülesannete vahel (näiteks üks üliõpilane loob vaateid, teine rutiine ja kolmas refaktoreerib tabeleid, võttes kasutusele domeenid). Soovitan ülesannete 2-4 puhul (kuid miks mitte ka ülejäänud ülesannete puhul) kasutada paarisprogrammeerimist (pair programming). https://en.wikipedia.org/wiki/Pair_programming https://www.infoq.com/articles/introducing-pair-programming/  Üks täiendab diagramme/programmeerib. Teised jälgivad, juhendavad, parandavad, mõtlevad kaasa. Vahetage vähemalt kord 30 minuti jooksul kirjutamisega tegelejat, et ühe sessiooni jooksul saaksid kõik projekti liikmed vähemalt korra kirjutamisega tegeleda. Paarisprogrammeerimine põhineb tähelepanekul (mida tuntakse Linuse seaduse nime all), et piisavalt paljude koodi vaatavate silmapaaride korral on kõik vead ülesleitavad.Isegi kui kasutate paralleeltööd, siis tagage, et kõik projekti osalised on tuttavad kogu projektis tehtuga, saavad sellest aru ning oskavad tehtud valikuid põhjendada! **Märksõnad:** paralleeltöö, paarisprogrammeerimine, Linuse seadus ## Küsimus: Kui teen kasutaja tuvastamiseks andmebaasis funktsiooni ja lisaks loon andmebaasis rakendusele vastava kasutaja, siis millise kasutajanime ja parooliga tuleb lõppkasutajal rakendusse sisse logida? **Vastus:** Teil on kaks kasutajanime/parooli komplekti. tXXXXXX ning hiljem Teie poolt loodud väiksemate õigustega andmebaasi kasutaja - need on loodud andmebaasis CREATE USER lausega. Seda kasutajanime/parooli kasutades loob rakendus andmebaasisüsteemiga ühenduse. Lõppkasutaja meiliaadress ja parool, mis on registreeritud andmebaasi tabelites (näiteks tabelites Isik ja Kasutajakonto) - neid kasutades logib lõppkasutaja rakendusse sisse ja saab selle pakutavatele andmetele ning tegevustele juurdepääsu. Rääkides MS Accessi andmebaasirakenduse näitel, siis moodulis Refreshing on see kasutajanimi/parool, mida kasutades võtab MS Accessi rakendus ühendust serverarvutis asuva andmebaasisüsteemiga. Peale seda kui ühendus on loodud saadab rakendus andmebaasisüsteemile kasutaja tuvastamise funktsiooni (nt f_on_juhataja) väljakutse, mille argumentideks on lõppkasutaja kasutajanimi ja parool. **Märksõnad:** access, salasõna ## Küsimus: Kuna avastasime, et meie grupil juhtus kodutöö versioonidega mingi viga ja kuhugi kadus parandatud kitsendustega versioon, siis hakkasin hiljem mõtlema, et kuidas edaspidi selliseid vigu vältida. Kas meie kodutöö raames on võimalik versioonihaldamiseks mingit versioonihalduse tarkvara kasutada, nt GitHub vms? **Vastus:** See ei ole kohustuslik, kuid on täiesti võimalik ja minu arvates hea mõte.Tallinna Tehnikaülikooli informaatika õppekavade üliõpilased kasutavad paljudes oma õppekava ainetes GitLabi ning seda kasutatakse ka bakalaureusetöö tegemisel. See on kättesaadav kõigile üliõpilastele, sest sisselogimine on Uni-IDga. Avaleht: https://gitlab.cs.ttu.ee/Alustamise juhend: https://pydoc.pages.taltech.ee/setup/git_ttu.html Projektihaldus GitLabis: https://projectdoc.pages.taltech.ee/Tean, et mitmed minu juhendatud üliõpilased on seda kasutanud nii lõputööde kui ka aineprojektide jaoks. Küsimuses mainitud GitHub sobiks muidugi samuti.   **Märksõnad:** GitLab, GitHub ## Küsimus: Miks on hindamismudelis nii palju võimalikke miinuspunkte? **Vastus:** Hindamismudeli leiate kataloogist Aine korraldus. Kõik need võimalikud miinuspunktid vastavad võimalikele vigadele, mida projektis võib teha. Nende sellisel viisil väljatoomise üks oluline eesmärk on anda võimalikult kiiresti ja võimalikult täpselt tagasisidet. Mida rohkem on väljatoodud vigu, seda kiiremini ja täpsemalt saab tagasisidet anda. Kiirust parandab, et konkreetse vea kohta pole vaja kommentaari nii pikalt välja kirjutada, sest see on antud juba vea kirjeldusega. Juba peale seda kui olin selle hindamismudeli kasutusele võtnud esines Tarkvarateaduse instituudi seminaril külalisettekandega Dr Antonette Mendoza, kes oli sellel ajal vanemlektor Melbourne'i Ülikoolis Austraalias. Tuleb välja, et seal on välja töötatud küllaltki sarnane süsteem suulistele eksamitele kiire tagasiside andmiseks. See süsteem on realiseeritud mobiiliäpina. Hindaja kuulab suulist vastust ning saab umbes 200 eeldefineeritud vea kirjelduse hulgast valida neid, mis iseloomustavad tema poolt kuulatavat vastust. Eelnevalt saab hindaja määrata vigadele kaalud. Hindamise käigus valitud vigade ja nende kaalude põhjal arvutab äpp hinde ja muudab selle koos vigadega hinnatavale nähtavaks. Täpsemal saab selle süsteemi kohta lugeda: Mendoza, A., Shallcross, D., 2016. Assessment and rapid feedback for oral presentations. Proceedings of Sixth International Symposium of Engineering Education. pp. 5-12 [WWW] link artiklit sisaldavale raamatule Veel üks programm, mis võimaldab miinuspunktide määramise kaudu kiiresti hinnata ja tagasisidet anda on Gradescope, mis on mõeldud paberil antud teadmiste kontrolli vastuste kiireks hindamiseks. Kasutaja saab näiteks hinnata vastuseid ülesannete kaupa (näiteks hinda kõigi tagastatud vastuste esimese ülesande lahendust). Hindamise juures saab defineerida rubriike, mis vastavad vastuses esinevatele vigadele. Hindaja saab määrata, kui mitu miinuspunkti saab sellise vea eest ning vastuse hindamisel saab ta rubriigi nimekirjast valida. Vaadake SIIT selle kohta lühikest videot.Hindamismudelis on mitmeid miinuseid välja toodud vaid sellepärast, et projekti saab teha ka vabal teemal. Tehes edasi eeldusaines alustatud töövihiku projekti või tehes projekti siin aines etteantud analüüsiprojekti järgi, ei ole võimalik neid vigu teha. Tegelikult saaks ka meie aines oleva hindamismudeli arendada edasi veebipõhiseks universaalseks süsteemiks, kus saaks hinnata erinevate õppeainete erinevaid teadmiste kontrolle. See võiks olla isegi üks lõputöö teema. Hindamismudeli eesmärgid on kokkuvõtlikult järgmised. Aidata anda tagasisidet võimalikult kiiresti. Võimaldada projekti tegijatel juba tegemise käigus teada saada, mida hinnatakse. Ühtlustada erinevate projektide hindamist selles mõttes, et nende hindamisel pööratakse tähelepanu samadele aspektidele ja seda tehakse samas mahus. Aidata vähendada hindamise subjektiivsust, st muuta hinne rohkem põhjendatuks. **Märksõnad:** Hindamismudel, hinne, Excel, projekt, iseseisev töö ## Küsimus: Milline on MINIMAALNE materjalide hulk, mille lugemisest piisab projekti edukaks tegemiseks? **Vastus:** Piisab hindamismudelist, mis deklareerib ootused projektile ning näiteprojektist kui NÄITEST (siin kataloogis) selle kohta, mis tuleb valmis saada. Võite läheneda arendusele testimispõhise arenduse põhimõttest lähtuvalt. Kõik hindamismudeli punktid on ühiktestid. Kõigepealt on nõue (mis peab olema projektis tehtud). Selle nõue kohta kirjutatakse test (sissekanne hindamismudelis), mis on ühtlasi nõude spetsifikatsioon. Testi esmakordselt jooksutades kukub see läbi, sest nõue pole täidetud. Seejärel tuleb teha projekti tulemites minimaalne muudatus, et nõue saaks täidetud ja test läbitud. Pidevalt tuleb tehtud tööd refaktoreerida. Erinevalt tarkvarast, kus ideaalis peaksid kõik ühiktestid vigadeta täidetud saama, on siin latt madalamal, sest osa teste võib ebaõnnestuda - peaasi, et vähemalt 31 punkti kokku tuleb. Siiski soovitan materjale rohkem lugeda, sest seal on kirjas, mitte ainult MIDA teha, vaid ka MIKS tuleb seda teha. Kas usaldaksite arsti, kes on õppinud selgeks plaastri peale panemise, süsti tegemise või retsepti väljakirjutamise protsessi, kuid ei tea midagi haigustest? Või kas usaldaksite prokuröri/kohtunikku/advokaati, kes teab küll kohtu protseduure, kuid seaduseid ei tunne ("Riigi Teataja on ju avalik allikas ja seda saab alati vajadusel guugeldada" - iroonia, kui keegi aru ei saanud). IT-spetsialistil on sama vastutusrikas töö. **Märksõnad:** hindamismudel, näiteprojekt, projekt, iseseisev töö ## Küsimus: Millised on kontrollpäringute süsteemile sarnased süsteemid? **Vastus:** Kontrollpäringute süsteem võimaldab andmebaasides sarnast analüüsi kui rakendustes programmid SonarQube ja PVS-Studio. Siit saate näitena lugeda kolme avatud lähtekoodiga andmebaasisüsteemi (PostgreSQL, MySQL, Firebird) koodi kvaliteedi võrdlust, milleks samuti kasutati lähtekoodi staatilist analüüsimist. Kontrollpäringutega ei analüüsita mitte otse lähtekoodi, vaid selle käivitamise tulemust (loodud andmebaasiobjekte). Tegemist ei ole siiski programmi dünaamilise analüüsiga, sest dünaamilise analüüsi korral käivitatakse programm erinevate sisenditega ja jälgitakse selle käitumist/väljundit. Andmebaaside korral tähendaks see erinevate päringute ja andmemuudatuste tegemist ning näiteks täitmisaja ning täitmiseks kasutatud plaanide jälgimist/uurimist.Sarnasteks programmideks on ka linterid, mis samuti võimaldavad koodi staatiliselt analüüsida ja leida süntaksivigu, turvaprobleeme, kodeerimise standarditest kõrvalekaldeid ja koodi halbade lõhnade esinemisi. On olemas mitmeid SQL koodi staatilise analüüsi vahendeid sh lintereid, mille nimekirja leiab SIIT. Linteriga kontrollitakse lauset enne käivitamist. Kontrollpäringud analüüsivad lausete täitmise tulemusel tekkinud andmebaasiobjekte. Kontrollpäringutega pole põhimõtteliselt võimalik kontrollida näiteks seda, kas lausetes on võtmesõnades suur- ja väiketähtede kasutamise stiil ühesugune või kas reavahetuste, tühikute ja taandridade kasutamine on sobiv. Küll aga saab selliseid asju kontrollida linteriga. Kontrollpäringute puhul tuleb ka arvestada sellega, et andmebaasisüsteem võib käivitatud lauset sisemiselt ümber kirjutada. Näiteks, oletame, et käivitan PostgreSQL andmebaasis lause:CREATE VIEW V_EMP_5 AS SELECT * FROM EMP ORDER BY EMPNO FETCH FIRST 5 ROWS ONLY;Andmebaasi süsteemikataloogis salvestatakse vaate nimi v_emp_5 (väiketähtedega), millel on järgmine alampäring: SELECT empno,    ename,    job,    mgr,    hiredate,    sal,    comm,    username,    password,    deptno   FROM emp  ORDER BY empno LIMIT 5;Algse lause probleemid, mida kontrollpäringud ei leia: Lause oli läbivalt suurtähtedega (sh nimed). Lause oli ühes reas. Lauses oli SELECT * Lausest puudusid OR REPLACE ja IF NOT EXISTS Lauses polnud näidatud sorteerimise suunda (ASC) Süsteemikataloogis salvestatud lauses kasutatakse vana süntaksi LIMIT 5, kuigi algses lauses oli kasutusel uus süntaks (FETCH FIRST 5 ROWS ONLY).Leidub programme, mis keskenduvad SQLi analüüsile.Üks populaarsematest SQL linteritest tundub olevat SQLFluff. Probleemid, mille mitteesinemist see tagada aitab, ei ühti üldiselt probleemidega, mida kontrollpäringutega kontrollitakse. SQLFluff linteriga saab põhiliselt kontrollida, kas SELECT lausete kirjapilt on "ilus" ja reeglipärane. Kokkulangevus on paari reegli osas (nt vältige piiritletud identifikaatoreid ja ärge kasutage võtmesõnu identifikaatoritena). Kuna päringute abil kontrollitakse üle 500 reegli, siis on kokkulangevate reeglite hulk väga pisike. dbcritic jõustab viis reeglit seoses tabelite struktuuriga. Nendest üks nõuab seda, et täisarvu tüüpi primaarvõtme veerud peaksid olema BIGINT tüüpi. Sellega ei tahaks nõus olla, sest täpsem andmetüübi valik annab andmebaasi skeemi vaatlejale infot andmete kohta (see on nagu osa andmebaasi dokumentatsioonist) ning aitab ka kokku hoida salvestusruumi.Vahend holistic teostab SQL lausete staatilist analüüsi ja suudab leida nendes probleeme 1300 reegli alusel. Nende probleemide parandamine peaks parandama andmebaasi struktuuri, andmekäitluse operatsioonide jõudlust ning isegi turvalisust. 28.10.2023 seisuga on toetatud PostgreSQL, kuid plaanis on lisada tugi ka teistele andmebaasisüsteemidele nagu Snowflake ja MySQL. Soovija saab sisselogimise järel vahendit katsetada. Uurisin selle vahendiga neid lauseid. holistic leidis 7 erinevat tüüpi vigu ja kokku 12 erinevat probleemi esinemist. Kontrollpäringud leidsid 64 erinevat tüüpi vigu. holisticu soovitus asendada igas olukorras VARCHAR(n) tüüpi veerg TEXT tüüpi veeruga koos CHECK kitsendusega maksimaalsele väljapikkusele tundub liiga ülepingutatud.sqlcheck kontrollib erinevate Karwini raamatus välja toodud andmebaasi disaini antimustrite esinemist koodis. Päringute antimustrite all on seal rohkem probleeme kui Karwini raamat välja toob. Ka kontrollpäringud sisaldavad selliseid kontrolle. Mis puudutab päringuid, siis kontrollpäringutes saab kontrollida vaadete ning hetktõmmiste alampäringuid ja rutiinides sisalduvaid päringuid. Kontrollpäringud kasutavad selleks mustripõhist otsingut regulaaravaldiste abil.Samas leidub ka programme, mis võimaldavad kontrollida erinevates keeltes kirjutatud koodi. Mõni nendest vahenditest realiseerib oma kontrollid ise. Näiteks vahend deepsource suudab kontrollida erinevates allikates olevat erinevates keeltes kirjutatud koodi. Toetatud keelte hulgas on ka SQL. Põhiliselt kontrollitakse stiilireeglitest kinnipidamist. Paljud kontrollitavad reeglid on seotud SELECT lausetega. Samas on ka selliseid programme, nagu MegaLinter, mis koondavad kokku erinevate osapoolte loodud lintereid.Kokkuvõte: SQL linterid ja kontrollpäringud täiendavad üksteis. Suurem osa linteri reeglitest on selle kohta, mida kontrollpäringutega ei saa kontrollida. Väiksem osa reeglitest langeb kokku kontrollpäringute reeglitega. **Märksõnad:** linter, automaatkontroll, kontrollpäring, kontrollpäringud ## Küsimus: Milliste andmete kogumist peaksin infosüsteemi projektis ette nägema? **Vastus:** Koguma peaks ainult selliseid andmeid, mida tööülesannete täitmiseks vaja läheb. Spordiklubid koguvad mõistliku põhjuseta isikuandmeid. Isikuandmete töötlemist reguleerib isikuandmete kaitse seadus. Seaduste mitte tundmine ei vabasta nende täitmisest. Infosüsteemid (sh andmebaasid) peavad olema kooskõlas seadustega - seadused moodustavad ühe osa keskkonnast, milles infosüsteemid ja andmebaasid eksisteerivad. ## Küsimus: Mul ei ole ühtegi kaaslast, kellega koos iseseisva töö projekti koos teha. Ometigi sooviksin kaaslase(id) leida. Mida teha? **Vastus:** Variandid (võib kasutada kõiki): Annate loengu või praktikumi alguses või lõpus oma soovist teistele osalejatele teada. Annate oma soovist teada õppeaine MS Teamsi rühmas. Saadate mulle enne projekti registreerimise tähtaega meili, et ma reklaamiksin Teie soovi õppeaine kodulehel. Iseseisva töö projekti registreerimisel on üks küsimus selle kohta, et kui teete projekti üksinda, siis kas soovite leida kaaslaseid. Kui vastate seal küsimusele jaatavalt, siis reklaamin samuti Teie soovi õppeaine kodulehel. NB! Kui leiate hiljem projekti tegemiseks kaaslase(d), siis tuleb sellest muudatusest mulle teada anda, muutes iseseisva töö teema registreerimise ülesande vastust. NB! Üksik üliõpilane ei saa liituda kahese projekti rühmaga peale kaheksanda õppenädala lõppu. Kõik muud liikumised rühmade sees ja vahel on lubatud kuni semestri lõpuni. ## Küsimus: Otsustasime meeskonnaga migreerida projekti Oracle -> PostgreSQL. Kas piisab sellest, et teeme vastav muudatus Iseseisva töö registreerimise lehel? **Vastus:** Jah, sellest piisab. --- # Teema: Oracle ## Küsimus: Kas Oracle andmebaasi saab laadida andmeid ka muul viisil kui väliste tabelite kaudu? **Vastus:** Jah saab, kasutades SQL*Loader vahendit. ## Küsimus: Kas Oracle SQL Developeris saab teha nii, et korraga näeb mitme tabeli kirjeldusi? **Vastus:** Jah saab. Täpsemalt kirjeldatakse seda siin: https://www.thatjeffsmith.com/archive/2013/05/how-to-see-two-tables-at-the-same-time-in-oracle-sql-developer/ Pakutakse välja kolm erinevat võimalust. Saab teha ka nii, et samaaegselt näeb kahte tabelit. ## Küsimus: Kas Oracles saab defineerida vaadetele kitsendusi? **Vastus:** Jah saab. Esiteks saab vaadetele lisada WITH CHECK OPTION (andmemuudatus vaate kaudu peab rahuldama vaate alampäringu tingimusi) ja WITH READ ONLY (vaade on ainult lugemiseks, st kirjutuskaitsega) kitsendused. Neid kitsendusi jõustatakse andmebaasisüsteemi poolt. Nendele kitsendustele saab soovi korral anda nime.Lisaks sellele saab vaadetele lisada PRIMARY KEY, UNIQUE ja FOREIGN KEY kitsendusi. Neid saab lisada ALTER VIEW lausega, kuid mitte määrata CREATE VIEW lauses. Neid kitsendusi andmebaasisüsteem ei jõusta, kuid andmebaasisüsteem või seda kasutavad programmid saavad kitsendustega antud taustainfot enda huvides ära kasutada (nt andmebaasisüsteem saab vaate põhjal tehtud päringule koostada parema täitmisplaani).Lisainfot:https://stackoverflow.com/questions/4435034/whats-the-point-of-a-view-constrainthttps://www.databasedesign-resource.com/constraints-on-views.htmlEesti keeles: Slaidid vaadete kohta (otsige fraasi: vaate kitsendused) **Märksõnad:** Oracle, vaade, kitsendus ## Küsimus: Kuidas saaks katsetada Oracle andmebaasisüsteemi uuemaid võimalusi, mida ülikooli serveris olev andmebaasisüsteemi versioon ei paku? **Vastus:** Oracle pakub katsetamiseks Oracle 23c põlvkonna andmebaasisüsteemi - Oracle 23c Free. Selle saab tööle panna Dockeri konteineris, kuid veel lihtsam on kasutada Oracle VM Virtual Box tarkvara ja käivitada seal Oracle poolt pakutav süsteemikujutis (system image) (hoiatus - selle suurus on umbes 6.5 GB ning allalaadimine võtab seega veidi aega).SIIN on laused, et luua andmebaasis tabelid Emp ja Dept, mille põhjal saaks erinevaid andmebaasikeele lauseid katsetada.Mis puudutab andmebaasi programmeerimist, siis toon järgnevalt välja mõned märkimisväärsed täiendused võrreldes Oracle 12.1 andmebaasisüsteemiga, mida Oraclesse aja jooksul on tehtud. Enamike andmebaasiobjektide nimi võib olla kuni 128 baiti (alates Oracle 12.2)(Oracle 12.1 ja varem võis enamike andmebaasiobjektide nimi olla kuni 30 baiti). Lisandus võimekus salvestada JSON dokumente, manipuleerida neid, teha nende põhjal päringuid ning esitada "tavaliste" tabelite põhjal tehtud päringu tulemus JSON formaadis. Palju täiendusi lisandus Oracle 23c põlvkonda nagu näiteks: võimalus luua domeene, võimalus kasutada BOOLEAN tabeli veeru tüübina, võimalus kirjutada SELECT lauset ilma FROM klauslit kasutamata (enam ei pea kasutama abitabelit Dual), võimalus lisada andmebaasiobjektidele annotatsioone (vabatekstilised võti-väärtus paarid), võimalus kasutada INSERT lauses VALUES alamosa nii, et ühe lausega lisatakse tabelisse mitu rida, võimalus luua mooduleid, kus on JavaScript funktsioonid ning võimalus luua mooduliväliseid rutiine, mille kehand on JavaScriptis, võimalus defineerida andmebaasis omaduste graafe (sisuliselt vaateid olemasolevate tabelite põhjal) ning teha sellise graafi põhjal uue süntaksiga päringuid. ## Küsimus: Kust saada head ja põhjalikku infot Oracle andmebaasisüsteemi kohta? **Vastus:** Üks hea koht Oracle kohta käivatele küsimustele vastuse saamiseks on Ask Tom lehekülg. Selle taga on Oracle ekspert Thomas Kyte koos abilistega. T. Kyte on kirjutanud ühed kõige paremad raamatud Oracle kohta nagu näiteks see (Kuidas kasutada O'Reilly digitaalset platvormi?). Ask Tom lehel esitavad inimesed üle maailma küsimusi Oracle kohta, neile vastatakse ning vastuste põhjal tekib sageli pikk diskussioon koos täiendavate (koodi)näidetega. ## Küsimus: Miks on Oracle's realiseeritud rutiinides vaja kasutada bind variables? **Vastus:** Hea selgitus. ## Küsimus: Milleks on hea Oracle kitsenduse seisund DISABLE VALIDATE? **Vastus:** Kui kitsendus luuakse sellises seisundis, siis andmemuudatuste korral kitsenduse kontrolli ei toimu, kuid tabelis olemasolevad andmed peavad olema kitsendusega kooskõlas - vastasel juhul kitsendust ei looda. Tsitaat Oracle dokumentatsioonist: "This feature is most useful in data warehousing situations, because it lets you load large amounts of data while also saving space by not having an index. This setting lets you load data from a nonpartitioned table into a partitioned table using the exchange_partition_subpart clause of the ALTER TABLE statement or using SQL*Loader. All other modifications to the table (inserts, updates, and deletes) by other SQL statements are disallowed." Ühesõnaga, tabelis olevad andmed peavad kitsendusele vastama, kuid uute andmete lisamisel kontrolli ei teostata. Andmeid saab sellisesse tabelisse lisada just SQL*Loader abil. **Märksõnad:** kitsendus ## Küsimus: Milliste andmeaida või andmevaka tabelite veergude puhul tasuks Oracles luua bitmap indekseid? **Vastus:** Iga erineva veerus oleva väärtuse kohta luuakse indeksis eraldi bitivektor. Seega, mida vähem on veerus erinevaid väärtuseid (teiste sõnadega, mida väiksem on erinevate väärtuste koguarvu protsent ridade koguarvust), seda vähem tuleb luua erinevaid bitivektoreid ning kasutada nendes 0-e ja seda efektiivsem on indeks. Mida vähem on bitivektoreid, seda vähem on indeksi plokke ja seda vähem on indeksi lugemiseks vaja plokkide lugemisi. Mida vähem lugemisoperatsioone on vaja mingi tulemuse saavutamiseks, seda kiiremini tulemus saavutatakse.Bitmap indeksi loomist võiks kaaluda välisvõtme veergude korral, mis viitavad klassifikaatorite alusel loodud dimensiooni tabelitele. Bitmap indeks ei sobi kindlasti veergudele, kus on unikaalsed või enamasti unikaalsed väärtused. **Märksõnad:** bitmap indeks, andmeait, andmevakk, dimensiooni tabel ## Küsimus: Millist regulaaravaldist tuleks kasutada Oracles, et kontrollida andmebaasi tasemel kolmetähelisi riigi koode? **Vastus:** Märkus: Paraku ei toeta Oracle andmebaasimootor BOOLEAN tüüpi ja seetõttu tuleb järgnevas PL/SQL anonüümses plokis tulemuse väljastamiseks asendada tõeväärtus tekstilise väärtusega. DECLARE result BOOLEAN; BEGIN result:=REGEXP_LIKE('EST', '^[A-Z]{3}$'); IF (result=true) THEN dbms_output.put_line('TRUE'); ELSE dbms_output.put_line('FALSE'); END IF; END; / Oracle APEXis, SQLclis ja SQL*Plusis annab see test tulemuseks TRUE, Oracle SQL Developeris (versioon 20.2) annab see tulemuseks FALSE. Kui tabelis on selline CHECK kitsendus (nt veerul riigi_kood), siis Oracle APEXis ja SQL Plusis õnnestub sellise CHECK kitsendusega tabelisse kenasti andmeid lisada. Samas SQL Developeris öeldakse andmete lisamisel (nt riik koodiga EST), et CHECK kitsenduse viga - nii INSERT lauseid käivitades, kui otse tabelisse andmeid lisades. Üha rohkem hakkab tunduma, et see on mingi SQL Developeri mulle tundmatu eripära. Soovi korral võite kasutada regulaaravaldise mustrit '^[[:upper:]]{3}$', mis toimib tõrgeteta kõigis minu kasutatud Oracle andmebaasisüsteemiga suhtlemiseks mõeldud keskkondades. Pange tähele, et mustrid '^[[:upper:]]{3}$' ja '^[A-Z]{3}$' pole samaväärsed, sest esimene lubab ka täpitähti (ÕÄÖÜ), kuid teine mitte. Kuna riikide koodides pole selliseid täpitähti, siis oleks mustrina eelistatud '^[A-Z]{3}$'. PostgreSQLis toimib regulaaravaldis '^[A-Z]{3}$' nii nagu peab. ## Küsimus: Teatavasti saavad Oracles (12c Release 1.0.1) enamik identifikaatoreid (nt tabelite ja kitsenduste nimed) olla maksimaalselt 30 baidi suurused. Kas on mõni abivahend, mis lihtsustakse andmebaasikeele lausete kirjutamisel selle pikkuse kontrollimist? **Vastus:** See veebipõhine vahend pakub võimaluse pikkust kontrollida. Meie kasutatavates CASE vahendites (Enterprise Architect, Rational Rose) pole paraku sellist kontrolli sisse ehitatud. Soovijad saaksid sellise vahendi luua, kasutades nende CASE vahendite laiendamise võimalusi, kuid see pole käesoleva kursuse teema. ## Küsimus: Teeme projekti Oracles ning mitmekesi. Millisesse andmebaasi tuleb panna rakenduse andmebaasiobjektid? Kuidas me üksteise tehtud andmebaasiobjektidele ligi pääseme? **Vastus:** Oracle andmebaas on serveris juba loodud. Logite Oracle serverisse olemasoleva andmebaasi kasutajana ja hakkate kasutama oma kasutajanimele vastavat skeemi. Kui loote mõne skeemiobjekti (nt tabeli), siis pannakse see Teie kasutajanimele vastavasse skeemi. Skeemile vastav kasutaja on kõigi oma skeemis olevate objektide omanik, st näeb neid ja saab hallata. Kõigil samal aastal serverile juurdepääsu saanutel on üks ja sama Oracle kasutajanimi ning parool, st kasutate ühte ja sama skeemi. Kui teete projekti mitmekesi, siis valige ühe enda rühma liikme matriklinumber, mida kasutate kõikides identifikaatorites (v.a tabellite veerud ning pakettides olevad rutiinid). Nii on SQL Developeris lihtne välja filtreerida just Teie rühma poolt loodud andmebaasiobjektid. Matriklinumbrite kasutamine identifikaatorites on vajalik, et vältida nimekonflikte (skeem on nimeruum). ## Küsimus: Üritan muuta Oracles tabeli struktuuri või tabelit kustutada, kuid saan veateate ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired. Milles on viga ja kuidas seda lahendada? **Vastus:** Viga tuleb sellest, et üritate kustutada tabelit, milles olevaid andmeid mõni teine transaktsioon samal ajal muudab. Lisan vastusele seda illustreeriva pildi. Sessioonis 1 loodi tabel ja lisati sellesse rida. INSERT lausega algas uus transaktsioon. Kuna Oracle ei tööta transaktsioonide automaatse kinnitamise režiimis, siis see transaktsioon kestab seni kuni see lõpetatakse või kestab sessioon, milles transaktsioon algatati. Kui tabelis andmeid muudetakse, siis paneb see tabelile luku, mis ei lase samal ajal tabeli struktuuri muuta või tabelit kustutada. Sellest tuleb sessioonis 2 veateade. Selline olukord saab tekkida, kui töötate tabelitega mitmekesi - üks muudab andmeid, teine tahab samal ajal neid kustutada. Lahenduseks on sessioonis 1 transaktsiooni lõpetamine. Transaktsiooni kinnitamiseks on COMMIT lause ja transaktsiooni tühistamiseks ROLLBACK lause. Peale seda võib sessioonis 2 uuesti kustutamist proovida. **Märksõnad:** lukustamine --- # Teema: PostgreSQL ## Küsimus: Kas isiku rollide omamise registreerimise võiks realiseerida nii, et luua loendustüüp rollide nimedega ning kasutajate tabelis luua veerg, mille väärtuseks on seda loendustüüpi väärtuste massiiv? **Vastus:** See on võimalik, aga ma ei soovita. Soovitan rollide jaoks luua eraldi klassifikaatori tabeli ja luua eraldi tabeli rollide omamiste kohta.CREATE TYPE t_roll AS ENUM('juhataja','administraator','tavakasutaja');CREATE TABLE Isik (isik_id SERIAL NOT NULL,rollid t_roll[] NOT NULL,CONSTRAINT pk_isik PRIMARY KEY (isik_id));Mis on selle lahenduse probleemid? 1. Isiku rollide hulga muutmiseks tuleb kogu massiiv uue väärtusega (massiiviga) asendada. 2. Massiiv võib sisaldada korduvaid elemente. 3. Kui rolli omamise kohta on vaja hakata koguma uusi andmeid (nt alguse ja lõpu aeg), siis tuleb kogu disain ümber teha. 4. Porditavus. Loendustüübid on PostgreSQL lisavõimalus. Massiivitüübi generaatori kasutamise võimalust näeb SQL standard ette, kuid erinevates süsteemides on erinevad kasutamise süntaksid ja põhimõtted. 5. Jõudlus. Järgnev katse tehti PostgreSQL (13) andmebaasis.   Tabelis health_care_visit_role on 1.3 miljonit rida.CREATE TABLE hcv_role_agg ASSELECT health_care_visit_id, array_agg(role_type_code) AS rolesFROM health_care_visit_roleGROUP BY health_care_visit_id;ALTER TABLE hcv_role_agg ADD CONSTRAINT pk_hcv_role_agg PRIMARY KEY (health_care_visit_id);   Päring ilma massiivita tabelist.EXPLAIN ANALYZE SELECT health_care_visit_id FROM health_care_visit_roleWHERE role_type_code='DOC03';Täitmise aeg umbes 160 ms   Päring tabelist, kus rollid on massiivis.EXPLAIN ANALYZE SELECT health_care_visit_id FROM hcv_role_aggWHERE 'DOC03'=ANY(roles);Täitmise aeg umbes 340 ms **Märksõnad:** enum, enumeration type ## Küsimus: Kas ja kuidas pääseb väljastpoolt ülikooli ligi õppeserverites olevatele PostgreSQL ja Oracle andmebaasisüsteemidele? **Vastus:** Serveritega seotud turvalisuse küsimustega tegeleb IT osakond. Nad on võtnud suuna sellele, et kaugligipääsudeks ülikooli serveritele peab hakkama kasutama autenditud VPNi. Kaugligipääs (st ligipääs väljastpoolt Tallinna Tehnikaülikooli arvutivõrku) apex2.ttu.ee PostgreSQL pordile ja apex.ttu.ee Oracle pordile on blokeeritud järgmiste eranditega. Kaugligipääs on võimalik: Tallinna Tehnikaülikooli wifist, väljastpoolt ülikooli (eduroamist, kodust vms) läbi FortiClient VPNi. Kui olete väljaspool ülikooli Eesti piires, siis FortiClient VPN ühenduse asemel võib PostgreSQL korral luua SSH tunneli (vt lisatud faili).Rakenduse tegijad peaksid arvestama järgnevaga. Kui teete kahekihilise süsteemi, kus rakendus on kliendi arvutis (nt kasutades MS Accessi või Javat), siis kodus rakendusega tegeledes on kõigepealt vajalik luua FortiClient VPN ühendus või kui olete Eestis, siis võib selle asemel PostgreSQL korral luua SSH tunneli. Muide, FortiClient VPN vahendusel saate kasutade ülikooli raamatukogu andmebaase, olles ise väljaspool Tallinna Tehnikaülikooli. Veebirakenduste tegijad - apex2.ttu.ee serveris on PHP ja pgApex. Kui soovite rakenduse jaoks kasutada mõnda muud serverit/vahendit, siis tuleks kas valida Tallinna Tehnikaülikooli võrgus olev server (mõnest teisest ainest) või luua rakenduses apex2.ttu.ee serveriga SSH ühendus (näide). Kuna väljaspool Eestit tuleb ka ssh ühenduse loomiseks luua FortiClient VPN ühendus, siis peaks server olema Eestis. Kui soovite väljaspool ülikooli PostgreSQLiga töötamiseks kasutada pgAdmini või Oraclega töötamiseks SQL Developerit siis tuleb teha ühte järgnevast. Luua kõigepealt FortiClient VPN ühendus. Eesti piires on PostgreSQL korral võimalik luua ühendus kasutades SSH tunnelit (vt lisatud faili). Selleks, et kasutada väljaspool ülikooli apex2.ttu.ee serveris psql programmi või apex.ttu.ee serveris SQL*Plus või SQLcl programmi, ei ole vaja Eesti piires midagi teistmoodi teha kui ülikooli ruumides - saate ssh protokolli kasutades serverisse logida ja programmi seal käivitada. Väljaspool Eestit tuleb kõigepealt luua FortiClient VPN ühendus. PostgreSQL andmebaas on kohustuslik paigutada apex2.ttu.ee serverisse ja Oracle andmebaas apex.ttu.ee serverisse, sest seal on automaattestimise vahendid ja õppejõul on sellele hindamiseks vajalik täielik juurdepääs. **Märksõnad:** ODBC,draiver, data source, andmeühenduse spetsifikatsioon, tunnel, FortiClient VPN, vpn, väljapool, väljapoolt, apex2 ## Küsimus: Kas ja milliseid lisavõimalusi SELECT lausete kirjutajale pakub PostgreSQL võrreldes MS Accessiga? **Vastus:** PostgreSQL (ja ka Oracle) pakuvad palju lisavõimalusi. Peaaegu kõik, mida õppisite MS Accessi baasil toimib ka PostgreSQLis või Oracles (võibolla väikeste süntaktiliste erinevustega). Kuid nendes süsteemides saab teha ka palju sellist, mida MS Access ei võimalda. Veendumaks, et selliseid lisavõimalusi on olemas, vaadake siia, kerige veidi allapoole, et leida PostgreSQLile pühendatud osa ning proovige seal olevaid SELECT lauseid nt pgAdmin abil käivitada. Need laused on panus projekti, mis üritab illustreerida erinevaid programmeerimiskeeli ühe ülesande lahenduse abil. Ülesandeks on genereerida ühe õllelaulu sõnad. Veel üheks allikaks mida uurida on SQLi viimasele sõnale pühendatud ajaveeb. Paljud seal kirjeldatud SQLi võimalused on olemas PostgreSQLis (ja Oracles), kuid mitte MS Accessis. ## Küsimus: Kas kuskil leidub iseseisvaid harjutusülesandeid PostgreSQL admebaasisüsteemi paremaks tundmaõppimiseks? **Vastus:** Huvitav keskkond neile, kes tahaksid veebipõhises interaktiivses keskkonnas rohkem PostgreSQLi harjutada. ## Küsimus: Kas ma saan õigesti aru, et PostgreSQLis tabeli nimed ei pea sisaldama üliõpilaskoodi, kuni script juba teeb ab skeemi, kus nimeks on t + üliõpilaskood? **Vastus:** Õppeserveris saab PostgreSQLis igaüks luua oma andmebaasi, kui vaja siis ka mitu. Andmebaasis saab luua skeeme. Oraclega sarnasel põhjusel nimekonfliktide tekkimine (kõik kasutavad sunduslikult ühe ja sama andmebaasi ühte ja sama skeemi) on sellega välistatud ja skeemiobjektide nimedes matriklinumbreid kasutada ei ole vaja - koodi parema loetavuse huvides on see lausa keelatud. Matriklinumbrit peab kasutama nimedes, mis peavad olema unikaalsed serveril asuvate andmebaaside klastri e kobara piires - andmebaasi nimi, andmebaasi kasutaja nimi, rolli nimi.PostgreSQLis ei looda andmebaasi loomisel automaatselt skeemi, mille nimi vastab Teie matriklinumbrile. Kui tahate, siis võite sellise teha, kuid see ei ole kohustuslik. PostgreSQL puhul rahuldub hindamismudel ka sellega, kui kõik loodavad skeemiobjektid on automaatselt loodavas skeemis public. ## Küsimus: Kas oleks otstarbekas siduda domeeniga mingi veeru omadus ja lisada sellele täiendav tabelipõhine piirang? Näiteks andmetüüp, NOT NULL ja tühikutest koosnemise piirang tulev domeeni poolt ja tabelis lisan täiendava piirangu pikkusele. **Vastus:** Tehniliselt oleks see võimalik. Ma mõtlen, et hallatavuse mõttes pole see kõige parem, sest pakutud juhul tuleb veerule rakenduvaid CHECK kitsendusi otsida (ja vajadusel muuta kahes kohas) - domeenis ja otse tabeli veeru küljes. ## Küsimus: Kas on mingit vahet selles osas, kui otsingutingimusse kirjutada IS TRUE või =TRUE? **Vastus:** Tegelikult ei ole. Teen väikese katsetuse PostgreSQLis (ver 16).CREATE TABLE Bool_test (bool_test_id SERIAL,flag BOOLEAN NOT NULL,CONSTRAINT pk_bool_test PRIMARY KEY (bool_test_id)); --Genereerin üks miljon rida juhuslike tõeväärtustegaINSERT INTO Bool_test (flag)SELECT (round(random())::int)::boolean AS flagFROM Generate_series(1, 1_000_000); Loon indeksi, värskendan statistikat ja katsetan kahte päringut.CREATE INDEX idx_bool_test_flag ON Bool_test(flag);ANALYZE;EXPLAIN ANALYZE SELECT Count(*) AS cnt FROM Bool_test WHERE flag IS TRUE;EXPLAIN ANALYZE SELECT Count(*) AS cnt FROM Bool_test WHERE flag=TRUE;Nendel päringutel pole PostgreSQLis vahet ei tulemuse ega kasutatud täitmisplaani seisukohalt. Mõlemate korral kasutatakse indeksit. Vahelepõikena olu öeldud, et see, et tulemus on ühesugune, on erinev MySQList, kus BOOLEAN on sünonüüm andmetüübile TINYINT(1) e väikeste täisarvude tüübile, mis sisaldab täisarve vahemikus -9 kuni 9. MySQLi korral tähendab väärtus 0 selles veerus tõeväärtust FALSE, kõik ülejäänud väärtused tõeväärtust TRUE. MySQLi puhul leiab IS TRUE tingimusega päring kõik read, kus flag väärtus ei ole 0, samas kui =TRUE tingimus leiab vaid read, kus flag väärtus on 1.Võimalik on ka selline kirjapiltSELECT * FROM Bool_test WHERE flag; Koodi ilmekuse seisukohalt mina sellist ei kasutaks.Vahe tuleb sisse, kui Boolean tüüpi veerus on lubatud NULLid. DROP TABLE Bool_test; CREATE TABLE Bool_test (bool_test_id SERIAL,flag BOOLEAN,CONSTRAINT pk_bool_test PRIMARY KEY (bool_test_id)); INSERT INTO Bool_test(flag) VALUES (TRUE),(FALSE),(NULL); SELECT * FROM Bool_test WHERE flag IS NOT TRUE;--Tulemuses kaks rida SELECT * FROM Bool_test WHERE flag<>TRUE;--Tulemuses üks rida, sest rida, kus flag on NULL, ei ole tulemuses.NULL Boolean tüüpi veerus tähistab tõeväärtust UNKNOWN. Kui lubate NULLe Boolean tüüpi veerus, siis kasutate kolmevalentset loogikat (kolm võimalikku tõeväärtust - TRUE, FALSE ja UNKNOWN), mis on asjatu keerukuse kasvatamine. See on piisav põhjus, et deklareerida BOOLEAN tüüpi veergudele NOT NULL kitsendus. ## Küsimus: Kas Oracle SQL Developer vahendi abil on võimalik töötada PostgreSQL andmebaasiga? **Vastus:** Jah on (vt seda artiklit ja allpool kasutamise juhendit).Oracle SQL Developer ei asenda pgAdmini, phpPgAdmini jms, sest selles saab teha vaid väikest hulka tegevusi, kuid midagi ikka. Täpsemalt on võimalik teha järgnevat. Vaadata tabelite struktuuri (veergude nimed ja järjekord). Baastabelite puhul näeb lisaks veeru tüüpi, kohustuslikkust, maksimaalset väljapikkust ja vaikimisi väärtust. Vaadata tabelites olevaid andmeid. Kopeerida baastabel Oracle andmebaasi. Valida saab, kas kopeerida tabel kui andmestruktuur, andmed (mõnda olemas olevasse tabelisse) või mõlemad. Vaadata baastabelite struktuuri ja kitsendusi diagrammina. Vaadata trigerite nimesid ja nende käivitatavate funktsioonide nimesid. Kõige rohkem võikski sellest olla kasu andmete ühekordsel ülekandmisel PostgreSQLi andmebaasist Oracle andmebaasi (st andmebaasi migreerimisel).Kasutamiseks tuleb teha järgnevat. Laadida SIIT alla JDBC draiver (jar fail). Tuleb valida kõige uuem versioon Java 8 jaoks. Allalaaditud jar fail tuleb panna SQL Developer kodukataloogis kataloogi: ...\jdk\jre\lib\ext Kui ei kasuta ülikooli Wifit, siis luua FortiClient VPN ühendus, sest muidu ei saa ülikooli serveris oleva PostgreSQLiga ühendust luua. Luua SQL Developeris uus ühenduse spetsifikatsioon (rohelise plussmärgiga nupp). Valida: Name: Ise valida (lubatud märgid: tähed, numbrid, @, _, -) Database Type: PostgreSQL Username: serveri kasutajanimi (t+matrikli number) Password: serveri parool (saatsite konto küsimisel meiliga) Hostname: apex2.ttu.ee Port: 5432 Vajutage nupule Choose Database ja valige liitboksist andmebaasi nimi. Kahjuks pole nimed tähestiku järjekorras. Vajutada nupule Test ja kui akna vasakusse alaserva ilmub teade Success, siis vajutada nupule Connect. ## Küsimus: Kas oskate soovitada kirjandust, kust saaks näiteid ja infot kuidas PostgreSQLis objekt-relatsioonilisest tulenevaid võimalusi ära kasutada ning sellega kaasnevaid plusse ja miinuseid (lisaks kasvavale keerukusele)? **Vastus:** PostgreSQL on objekt-relatsiooniline andmebaasisüsteem. Kirjutan objekt-relatsioonilisusest SIIN. Muuhulgas on seal ka pikemalt koos koodinäidetega juttu PostgreSQLi objekt-relatsioonilisuse võimalustest.Objekt-relatsioonilisusest (OR) tulenevate võimaluste kasutamist ei ole ma päriselu andmebaasides väga palju kohanud. Mulle endale tundub pakutavatest võimalustest kõige kasulikum massiivitüüpide kasutamine veergude ja parameetrite tüüpidena, uute vahemiku tüüpide loomine ning kasutamine ja operaatorite loomine. Kui lugeda OR võimaluste hulka ka andmebaasis suurte objektide (nt failide) salvestamine, siis on ka see kasulik.Uute baastüüpide loomine - võimalik, kuid PostgreSQLi juba olemasolevate andmetüüpide suur hulk tähendab, et see on vajalik pigem erandjuhtudel.Loendustüüpide kasutamine veeru tüüpidena - selle asemel oleks parem luua klassifikaatorite tabelid, millele välisvõtmete kaudu viidatakse. Loendustüüpide veeru tüübina kasutamise probleemide kohta on kirja pandud SQL disaini antimuster (Kirjelda veeru võimalikud väärtused osana veeru definitsioonist), mida kirjeldatakse SQL-andmebaaside disaini antimustrite raamatu 11. peatükis:https://learning.oreilly.com/library/view/sql-antipatterns/9781680500073/f_0068.htmlTabelite loomine pärimise kaudu - tõsiseks piiranguks on, et alamtüüpi olem ei kuulu välisvõtme kitsenduse kontrolli mõttes ülatüüpi. Lisaks eelviidatud dokumendile kirjutatakse pärimise kaudu tabelite loomise võimalustest ja probleemidest SIIN alates slaidist "Baastabelite loomine pärimist kasutades" (slaidid 16-22).Mõned lõputööd, kus neid teemasid on käsitletud: Mitme väite ühe andmeväärtusena esitamise eelised ja puudused SQL-andmebaasides Käsitletakse muuhulgas andmete hoidmist andmebaasis massiividena Veel massiivide kasutamise näiteid Funktsioonis Tabelifunktsioonis ja vaates Oracle ja PostgreSQL andmebaasisüsteemide objekt-relatsiooniliste võimaluste võrdlus panga infosüsteemi andmebaasi alamosa näitel Juba vana ja mitte nii põhjalik kui soovinuks Mõned failide salvestamise disainimustrid SQL-andmebaasi kasutavate andmebaasirakenduste jaoks Suurte objektide hoidmine PostgreSQL andmebaasis **Märksõnad:** objekt-relatsiooniline, massiiv, array, enumeration type, operaator, pärimine ## Küsimus: Kas PostgreSQLi DATE ja TIMESTAMP tüüpi veergude kitsenduste puhul tuleb arvestada spetsiaalväärtusega 'infinity'? **Vastus:** Jah, mõnikord tuleb. Toon näite.PostgreSQLi DATE ja TIMESTAMP tüüpidesse kuuluvad spetsiaalväärtused 'infinity' (suurem kui kõik ülejäänud DATE/TIMESTAMP väärtused) ja '-infinity' (väiksem kui kõik ülejäänud DATE/TIMESTAMP väärtused).CREATE TABLE Bronn (bronn_id SERIAL,ruumi_nr INTEGER NOT NULL,alguse_aeg TIMESTAMP NOT NULL,lopu_aeg TIMESTAMP NOT NULL DEFAULT 'infinity',CONSTRAINT pk_bronn PRIMARY KEY (bronn_id),CONSTRAINT ak_bronn UNIQUE (ruumi_nr, alguse_aeg),CONSTRAINT chk_bronn_alguse_aeg CHECK(alguse_aeg>='2020-01-01' AND alguse_aeg<'2200-01-01'),CONSTRAINT chk_bronn_lopu_aeg CHECK(lopu_aeg>='2020-01-01' AND lopu_aeg<'2200-01-01'));INSERT INTO Bronn (ruumi_nr, alguse_aeg)VALUES (1, '2022-10-04 12:00'),(2, '2022-10-04 12:00');/*Lisamine ebaõnnestubERROR:  new row for relation "bronn" violates check constraint "chk_bronn_lopu_aeg"DETAIL:  Failing row contains (1, 1, 2022-10-04 12:00:00, infinity).*/ALTER TABLE Bronn DROP CONSTRAINT chk_bronn_lopu_aeg;ALTER TABLE Bronn ADD CONSTRAINT chk_bronn_lopu_aeg CHECK(lopu_aeg>='2020-01-01' AND lopu_aeg<'2200-01-01' OR lopu_aeg='infinity');INSERT INTO Bronn (ruumi_nr, alguse_aeg)VALUES (1, '2022-10-04 12:00'),(2, '2022-10-04 12:00');/*Lisamine õnnestub*/ **Märksõnad:** PosgtreSQL, andmetüüp, andmetüübid, spetsiaalväärtus, spetsiaalväärtused, CHECK kitsendus ## Küsimus: Kas PostgreSQLi loendustüüpi võiks kasutada väga harva muutuvate klassifikaatorite (näiteks seisundite liigid) realiseerimiseks? **Vastus:** See on võimalik, aga ma ei soovita. Soovitan nende asemel luua ja kasutada klassifikaatorite tabeleid.CREATE TYPE t_tellimuse_seisundi_liik AS ENUM('loodud','kinnitatud','tühistatud','täidetud');CREATE TABLE Tellimus (tellimus_id SERIAL NOT NULL,tellimuse_seisundi_liik t_tellimuse_seisundi_liik DEFAULT 'loodud' NOT NULL,CONSTRAINT pk_tellimus PRIMARY KEY (tellimus_id));Selles artiklis nimetatakse ja hinnatakse erinevaid võimalusi, kuidas piirata väärtuste hulka, mida PostgreSQL tabeli veerus saab salvestada. Üheks võimaluseks on kasutada veeru tüübina loendustüüpi. Artikkel toob kenasti välja selle lähenemise eelised ja puudused ning ütleb, et seda sobiks kasutada (mis ei tähenda, et seda peab kasutama) seisundite registreerimiseks. Lisaks artiklis nimetatud probleemidele toon välja veel kaks.1.Kuna lahenduses puuduvad klassifikaatoritel koodid, siis on andmete süsteemisisene esitus ja andmete kasutajatele esitus liigselt läbipõimunud. Klassifikaatoritel on üldiselt koodid ja nimetused (https://klassifikaatorid.stat.ee/?siteLanguage=ee). Koode kasutatakse süsteemi sees, nimetusi kuvatakse kasutajatele.   Selles süsteemis on nimetused ühtlasi koodide eest, mis tähendab, et kui arusaadavuse parandamiseks tuleb kasutajale esitatavat nimetust muuta, siis tuleb muuta kõiki andmebaasikeele lauseid, milles vana nimetust kasutati.   SELECT * FROM Tellimus WHERE tellimuse_seisundi_liik='loodud';2.Üheks loendustüüpi veergude kasutamise õigustuseks on, et ei ole tõenäoline, et nende abil esitatavate olemitüüpide kohta oleks vaja hakata registreerima täiendavaid andmeid. Milliseid andmeid võiks siiski olla üsna tõenäoliselt vaja tellimuse seisundi liikide kohta veel koguda? Klassifikaatori väärtuse vabatekstiline kirjeldus. Seisund. Mõned klassifikaatori väärtused võivad muutuda mitteaktiivseks, st neid võidi kasutada minevikus, kuid neid ei saa enam kasutada uute olemite iseloomustamiseks. Mitmekeelne sisu - erinevad klassifikaatori nimetused erinevates keeltes süsteemi kasutajatele (ingliskeelses kasutajaliideses peaks seisundi nimi olema "created", mitte "loodud"). Neid lahendusi siin Te kasutada ei saaks: https://digikogu.taltech.ee/et/Item/3c203fdf-0162-4545-a3d8-fcfa150f5301 ## Küsimus: Kas PostgreSQLis ON DELETE CASCADE kasutamine välisvõtme deklaratsioonis põhjustab halba kustutamise töökiirust e jõudlust? **Vastus:** Ei tekita.Põhjendan vastust. Tegin katsetusi PostgreSQL 15 andmebaasis, millel on järgmine kontseptuaalne struktuur:[Facility]-0..1-----------------0..*-[Health_care_visit]Tabel Facility: 50 000 ridaTabel Health_care_visit: 1 000 00 ridaTabelis Health_care_visit on 6 rida, kus facility_id=200Tabelis Health_care_visit on indeks veerul facility_id.Katsetasin kahe ülesande täitmist: Ül1: Kustuta tervishoiuasutus, mille id=200 ja selle asutusega seotud külastused. Ül2: Kustuta kõik tervishoiuasutused ja nende asutustega seotud külastused. Katsetasin nende ülesanne täitmist kahe andmebaasi disaini korral. D1: Välisvõtme kitsendusega on seotud ON DELETE CASCADE kompenseeriv tegevus. See tähendab, et kustutasin ridu ainult tabelist Facility ja seotud read kustutati kaskaadselt tabelist Health_care_visit. DELETE FROM Facility WHERE facility_id=200; DELETE FROM Facility; D2: Välisvõtme kitsendusel ei ole ON DELETE CASCADE kompenseerivat tegevust. See tähendab, et kõigepealt tuli kustutada read tabelist Health_care_visit ja siis sai kustutada read tabelist Facility. DELETE FROM Health_care_visit WHERE facility_id=200;DELETE FROM Facility WHERE facility_id=200; DELETE FROM Health_care_visit;DELETE FROM Facility; Viisin iga ülesande ja disaini paari korral kustutamist läbi viis korda ja leidsin süsteemi kulutatud aja (lausete täitmisplaani koostamine + plaani täitmine) keskmiseÜl1, D1 (ON DELETE CASCADE): 0.94 msÜl1, D2 (ON DELETE NO ACTION): 0.77 msÜl2, D1 (ON DELETE CASCADE): 4975 msÜl2, D2 (ON DELETE NO ACTION): 7409,204 msNagu näha, siis primaarsest tabelist (vanemtabelist) ühe rea kustutamisel oli ON DELETE CASCADE lahendus veidi aeglasem, kuid mõlemad lahendused olid aktsepteeritava töökiirusega. Primaarsest tabelist (vanemtabelist) kõikide ridade kustutamisel oli ON DELETE CASCADE lahendus palju kiirem, kusjuures operatsiooni läbiviimine võttis mõlemal juhul palju aega.Kokkuvõttes järeldan, et töökiirus ei peaks olema argument, miks ON DELETE CASCADE mitte kasutada.NB! Eelnev näide põhineb ühel andmebaasisüsteemi versioonil. Teistes andmebaasisüsteemides või versioonides võivad tulemused olla erinevad. ## Küsimus: Kas PostgreSQLis peaks vaate alampäringus kasutama SELECT ... FOR UPDATE? **Vastus:** Ei! Tõsi on see, et PostgreSQLis saab erinevalt Oraclest (12.1) vaate alampäringus kasutada SELECT ... FOR UPDATE. Siin kirjutatakse sellest pikemalt koos viitega laiendusel pgrowlocks, mis võimaldab hästi jälgida ridadele pandud lukke.CREATE OR REPLACE VIEW Emp_all ASSELECT *FROM Emp INNER JOIN Dept USING (deptno) FOR UPDATE;Kui nüüd keegi käivitab laused:START TRANSACTION;SELECT * FROM Emp_all;, siis lukustatakse selle sessiooni jaoks eksklusiivselt kõik read tabelites Emp ja Dept. Teiste sõnadega, teistes sessioonides ei saa tabelites Emp ja Dept andmeid muuta, kuni selles sessioonis pole see transaktsioon lõppenud. See takistaks liiga palju andmebaasi samaaegset kasutamist erinevate kasutajate poolt ja pole seega soovitav. Seega SELECT .. FOR UPDATE vaates kasutama ei peaks.SELECT ... FOR UPDATE tuleks näiteks kasutada rutiinides (nii eraldiseisvad kui trigeritega seotud) olevates kontrollpäringutes või andmemuudatuse lausete andmete kontrollimiseks mõeldud alampäringutes. Kui muudan andmeid tabelis A ja pean selleks kontrollima andmeid tabelist B, kuid samal ajal soovib keegi teine tabelis B neid samu kontrollimise aluseks olevaid andmeid muuta, siis tegemist on konfliktsete operatsioonidega, mis peaksid toimuma järjekorras, mitte samaaegselt. SELECT ... FOR UPDATE aitab seda saavutada. **Märksõnad:** lukustamine, vaade, PostgreSQL, eksklusiivne lukk, triger, trigerid, alampäring ## Küsimus: Kas PostgreSQLis saab genereerida fraktaleid nagu demonstreerib see projekt MS SQL Serveri põhjal? **Vastus:** Jah, PostgreSQLis kirjutatud rekursiivsete SELECT lausetega saab genereerida fraktaleid. Näiteid leiab SIIT. Võite nende päringute käivitamiseks kasutada mistahes kursuse serveri andmebaasi. Kasutage käivitamiseks programme psql või pgAdmin. ## Küsimus: Kuidas jõustada PostgreSQLis kitsendus, et kui üks ja sama töötaja omab ühte ja sama rolli mitu korda, siis ei tohi rolli omamise ajaperioodid kattuda? **Vastus:** Tuleb luua EXCLUDE kitsendus. EXCLUDE kitsendus on unikaalsuse kitsenduse edasiarendus, mille puhul saab väärtuste unikaalsuse e kordumatuse kontrollimiseks kasutada ka mõnda muud operaatorit kui võrdsuse kontrolli operaator (=), mida kasutab UNIQUE kitsendus. Vaadake täpsemat näidet slaidikomplektist. Otsige sealt fraasi "Kattuvate perioodide vältimine". ## Küsimus: Kuidas katkestada PostgreSQLis SQL lause, mille täitmine võtab liiga kaua aega? **Vastus:** Looge uus andmebaasi ühendus. Te võite ülikasutajana ühenduda ka mõne muu andmebaasi külge, kui see, milles töötab liiga kaua täidetav lause.Leidke liiga kaua täidetava lause pid kasutades päringut: SELECTpid,now() - pg_stat_activity.query_start AS duration,query,stateFROM pg_stat_activityWHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'; Päring leiab laused, mille täitmine on võtnud aega üle 5 minuti.Lõpetage lause täitmine, andes korralduse: SELECT pg_cancel_backend(--pid--);Näide:SELECT pg_cancel_backend(3847609); ## Küsimus: Kuidas kiirendada PostgreSQLis päringuid, kus päringu tingimuses kontrollitakse stringi vastavust mustrile (nt leia isikud, kelle perenimi algab M tähega)? **Vastus:** Looge tekstilisele veerule indeks ja kasutage selle puhul operaatori klassi, mis pole vaikimisi klass. TEXT tüüpi veeru korral kasutage operaatori klassi text_pattern_ops, VARCHAR tüüpi veeru korral varchar_pattern_ops ja CHAR tüüpi veeru korral char_pattern_ops. Operaatori klass määrab, milliste operaatorite kasutamise korral päringu tingimuses seda indeksit saaks kasutada. Eelnimetatud operaatori klassid võimaldavad, indeksit kasutada mustripõhise otsingu korral, kui soovitakse otsida stringi alguse järgi.Järgnev näide on tehtud läbi PostgreSQL (16) põhjal.Loon tabeli.CREATE TABLE Isik (eesnimi VARCHAR(50) NOT NULL,perenimi VARCHAR(50) NOT NULL);Lisan tabelisse juhuslikult genereeritud 100 000 ees- ja perenime pikkusega 1 kuni 50 märki. Nimedes kasutatakse eesti tähestiku tähti.INSERT INTO Isik(eesnimi, perenimi)SELECT (SELECT initcap(string_agg(substring('abcdfghijklmnopqrstuvwõäöüxyz', floor(random() * (29 - 1 + 1) + 1)::int, 1), '')) AS string FROM generate_series(1, floor(random() * (50 - 1 + 1) + 1)::int+(generator*0))) AS eesnimi,(SELECT initcap(string_agg(substring('abcdfghijklmnopqrstuvwõäöüxyz', floor(random() * (29 - 1 + 1) + 1)::int, 1), '')) AS string FROM generate_series(1, floor(random() * (50 - 1 + 1) + 1)::int+(generator*0))) AS perenimiFROM generate_series(1, 100_000) AS generator;Loon eesnime veerule B+ puu indeksi (see on vaikimisi indeksi tüüp), kus veergude puhul kasutatakse vaikimisi operaatori klassi.CREATE INDEX idx_isik_nimi ON Isik(perenimi, eesnimi);Värskendan andmebaasi statistikat.ANALYZE;EXPLAIN ANALYZE SELECT *FROM IsikWHERE eesnimi='Mart'AND perenimi='Mets';Päringu täitmiseks kasutatakse indeksit. Toimub Index Only Scan operatsioon ning andmeid loetakse ainult indeksist, ilma tabeli poole pöördumata.Täitmisplaani täitmiseks kulub 0.303 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE eesnimi='Mart';Päringu täitmiseks ei kasutata indeksit, sest otsitakse vaid eesnime järgi. Samas tegemist on liitindeksiga, kus esimesel kohal on perenimi.Täitmisplaani täitmiseks kulub 11.456 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi<'Mets';Päringu täitmiseks kasutatakse indeksit. Toimub Index Only Scan operatsioon ning andmeid loetakse ainult indeksist, ilma tabeli poole pöördumata.Täitmisplaani täitmiseks kulub 11.499 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi<>'Mets';Päringu täitmiseks ei kasutata indeksit. Toimub Seq Scan operatsioon ning andmeid loetakse ainult tabelist, ilma indeksi poole pöördumata.Täitmisplaani täitmiseks kulub 20.710 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi LIKE 'M%';Päringu täitmiseks ei kasutata indeksit. Toimub Seq Scan operatsioon ning andmeid loetakse ainult tabelist, ilma indeksi poole pöördumata.Täitmisplaani täitmiseks kulub 14.647 ms.Kustutan indeksi.DROP INDEX idx_isik_nimi;Loon indeksi uuesti kasutades operaatori klassi varchar_pattern_ops.CREATE INDEX idx_isik_nimi ON Isik(perenimi varchar_pattern_ops, eesnimi varchar_pattern_ops);Indeksi suurus on peaaegu sama kui eelneval indeksil, ehki mitte identne.ANALYZE;EXPLAIN ANALYZE SELECT *FROM IsikWHERE eesnimi='Mart'AND perenimi='Mets';Päringu täitmiseks kasutatakse indeksit. Täitmisplaani täitmiseks kulub 0.112 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE eesnimi='Mart';Päringu täitmiseks ei kasutata endiselt indeksit.Täitmisplaani täitmiseks kulub 11.133 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi<'Mets';Päringu täitmiseks ei kasutata enam indeksit. NB! kui tahaksin teha päringuid tingimustega, kus kasutatakse >=, >, < või <= operaatoreid, siis võiks lisaks luua ka vaikimisi operaatori klassiga indeksi, mida andmebaasisüsteem saaks kasutada selliste päringute täitmiseks. Ühel ja samal tabeli veerul võib olla mitu indeksit.Täitmisplaani täitmiseks kulub 21.644 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi<>'Mets';Päringu täitmiseks ei kasutata endiselt indeksit.Täitmisplaani täitmiseks kulub 19.372 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi LIKE 'M%';Päringu täitmiseks kasutatakse indeksit, sest lisatud indeks võimaldab otsida stringi alguse järgi.Täitmisplaani täitmiseks kulub 2.536 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE eesnimi LIKE 'M%'AND perenimi LIKE 'M%';Päringu täitmiseks kasutatakse indeksit, sest lisatud indeks võimaldab otsida stringi alguse järgi.Täitmisplaani täitmiseks kulub 0.402 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi ~ '^M';Päringu täitmiseks kasutatakse indeksit, sest lisatud indeks võimaldab otsida stringi alguse järgi.Täitmisplaani täitmiseks kulub 2.384 ms.EXPLAIN ANALYZE SELECT *FROM IsikWHERE perenimi LIKE '_M%';Päringu täitmiseks ei kasutata indeksit, sest teadaolev stringi osa pole stringi alguses.Täitmisplaani täitmiseks kulub 11.936 ms. **Märksõnad:** generate_series, testandmete genereerimine, indeks ## Küsimus: Kuidas kutsuda PostgreSQLis välja funktsiooni või protseduuri, mille mõni parameeter on SMALLINT tüüpi? **Vastus:** Oletame, et andmebaasis on loodud funktsioon f_lopeta_teenus, mille parameeter p_teenuse_kood on SMALLINT tüüpi. Üritades seda funktsiooni välja kutsuda lausega: SELECT f_lopeta_teenus(p_teenuse_kood:=436); on tulemuseks veateade: ERROR: function f_lopeta_teenus(p_teenuse_kood => integer) does not exist LINE 1: select f_lopeta_teenus(p_teenuse_kood:=436); Käivitatav funktsioon valitakse argumentide tüüpide alusel. Vaikimisi eeldus on, et literaali 436 poolt esitatav väärtus kuulub tüüpi INTEGER. Kuid funktsiooni parameeter on hoopis tüüpi SMALLINT. Seega korrektseks väljakutseks on vajalik lause: SELECT f_lopeta_teenus(p_teenuse_kood:=436::SMALLINT); ::SMALLINT teeb tüübiteisenduse tüüpi SMALLINT. ## Küsimus: Kuidas leida PostgreSQLis teatud kindla nimega andmebaas või andmebaas, millel on teatud kindel omanik? **Vastus:** Otsin näitena andmebaasi, mille nimes sisaldub 990999 või mille omaniku kasutajanimes sisaldub 990999.Ühenduge psqlis suvalise kasutaja andmebaasiga (kuid mitte andmebaasiga postgres). Andke käsk\l *990999*Näete nimekirja andmebaasidest, mille nimes sisaldub 990999.Käivitage süsteemikataloogi päring:SELECT datname, pg_encoding_to_char(encoding) AS encoding, datcollate, datctype, rolname AS ownerFROM pg_database INNER JOIN pg_authid ON pg_database.datdba=pg_authid.oidWHERE datname LIKE '%990999%'OR rolname LIKE '%990999%'ORDER BY datname, rolname;Näete nimekirja andmebaasides, mille nimes või omaniku nimes sisaldub 990999.Süsteemikataloogi andmebaasis pg_database on andmed kõigi serveril loodud andmebaaside kohta. ## Küsimus: Kuidas leida päringuga koondandmed, kus iga olemi kohta on üks rida ning selles reas on massiiv selle olemiga otseselt või kaudselt seotud olemite andmetest? **Vastus:** See, kas seda saab üldse SQLiga lahendada ja kuidas seda lahendada sõltub andmebaasisüsteemist.Järgnev näide on tehtud PostgreSQLis. Oletame, et andmebaasi kontseptuaalne struktuur on:[Hotell]-1------0..*-[Ruum]-1-----------0..*-[Reserveerimine]-0..*-------1-[Külaline]Ülesandeks on leida kõik hotellid ja näidata päringu tulemuses iga hotelli kohta üht rida. Selles reas peavad olema ka andmed seotud ruumide, reserveerimiste ja külaliste kohta. WITH res AS (SELECT ruumi_nr, hotelli_nr, array_agg(row(kylalise_nr, perenimi, alguse_aeg, lopu_aeg) ORDER BY alguse_aeg, kylalise_nr) AS reserveerimised FROM Reserveerimine INNER JOIN Kylaline USING (kylalise_nr) GROUP BY ruumi_nr, hotelli_nr), ruumid AS (SELECT Ruum.ruumi_nr, Ruum.hotelli_nr, ruumi_tyyp, hind, reserveerimised FROM Ruum LEFT JOIN Res USING ( ruumi_nr, hotelli_nr)) SELECT Hotell.hotelli_nr, nimi, linn, array_agg(row(ruumi_nr, ruumi_tyyp, hind, reserveerimised) ORDER BY ruumi_nr) AS ruumid FROM Hotell LEFT JOIN ruumid USING (hotelli_nr) GROUP BY Hotell.hotelli_nr, nimi, linn ORDER BY hotelli_nr; Päring leiab kõik hotellid.  Iga hotelli kohta esitatakse selle hotelli ruumide massiiv.  Massiivi elementideks on read, kus ühes väljas olevaks väärtuseks on selles ruumis toimunud reserveerimiste ridade massiiv.PostgreSQLis on koondandmete massiivide leidmiseks funktsioon array_agg. Funktsiooni row kasutatakse rea konstrueerimiseks.Päringu tulemuse näide on vastusele lisatud failis. **Märksõnad:** koondandmed, massiiv ## Küsimus: Kuidas piirata ridu, mille põhjal kokkuvõttefunktsioon arvutab tulemuse? **Vastus:** Oletame, et andmebaasi kontseptuaalne struktuur on selline:[Dept]-1---------0..*-[Emp]Iga osakond (Dept) on seotud null või rohkem töötajaga (Emp).Iga töötaja (Emp) on seotud täpselt ühe osakonnaga (Dept).1. Leidke iga osakonna kohta selles müügimehe ametikohal töötavate töötajate arvu. Väljastage osakonna number, nimi ja sellel ametikohal töötavate töötajate arv.SELECT deptno, dname, Count(*) FILTER (WHERE job='SALESMAN') AS nr_of_salesmenFROM Dept LEFT JOIN Emp USING (deptno)GROUP BY deptno;Tähelepanekuid. Pean kasutama LEFT JOIN, et tulemuses oleks ka osakonnad, kus pole ühtegi töötajat. Saan grupeerida ainult osakonna numbri järgi, sest PostgreSQL saab antud juhul aru, et osakonna number identifitseerib üheselt osakonna nime. Seega pole osakonna nime veergu vaja GROUP BY klauslis korrata. FILTER kasutamine on PostgreSQLi poolne SQLi laiendus ja võimaldab lauseid kompaktsemalt kirja panna. Alternatiiv oleks kasutada CASE avaldist: SELECT deptno, dname, Count(CASE WHEN job='SALESMAN' THEN 1 ELSE NULL END) AS nr_of_salesmenFROM Dept LEFT JOIN Emp USING (deptno)GROUP BY deptno;2. Leidke iga osakonna kohta müügimehe ametikohal töötajad. Väljastage osakonna number, nimi ning komadega eraldatud nimekiri sellel ametikohal töötavate töötajate nimedest sorteerituna töölevõtmise aja järgi kasvavalt. Väljastage iga osakonna kohta maksimaalselt kaks nime. WITH hiring AS (SELECT deptno, ename, DENSE_RANK() OVER(PARTITION BY deptno ORDER BY hiredate) AS rankFROM EmpWHERE job='SALESMAN'),selected AS (SELECT deptno, ename, rankFROM hiringWHERE rank<=2ORDER BY rankFETCH FIRST 2 ROWS ONLY)SELECT deptno, dname, string_agg(ename, ',' ORDER BY rank) AS personsFROM Dept LEFT JOIN selected USING (deptno)GROUP BY deptno;hiring - ühine tabeli avaldis (common table expression, CTE), millega leian müügimehe ametikohal töötajad ning nende asukoha osakonna töötajate töölevõtmise järjekorra pingereas. Kasutan tiheda pingerea leidmise funktsiooni dense_rank. Tihe pingerida tähendab, et asetustesse ei jää auke. selected - leian eelnevalt defineeritud ühise tabeli avaldise alusel töötajad, kelle nimed tuleb väljastada. põhipäring - leian osakonnad ja panen iga osakonna kohta kokku töötajate nimede stringi kasutades kokkuvõttefunktsiooni string_agg.   3. Kui ülesandeks oleks väljastada iga osakonna kohta töötajad, kes on tööle võetud kahel esimesel kuupäeval, siis oleks lahendus selliseid. Pange tähele, et selliseid töötajaid võib olla rohkem kui kaks.   WITH hiring AS (SELECT deptno, ename, DENSE_RANK() OVER(PARTITION BY deptno ORDER BY hiredate) AS rank FROM Emp WHERE job='SALESMAN') SELECT deptno, dname, string_agg(ename, ',' ORDER BY rank) FILTER (WHERE rank<=2) AS persons FROM Dept LEFT JOIN hiring USING (deptno) GROUP BY deptno; **Märksõnad:** ühine tabel avaldis, common table expression, cte, with, filter, agregeerimine, kokkuvõttefunktsioon, dense_rank, aknafunktsioon ## Küsimus: Kuidas registreerida PostgreSQLi andmebaasis hetke kuupäev+kellaaeg ilma ajavööndi infota ja ilma sekundi murdosadeta? **Vastus:** CREATE TABLE Ajatempel(tempel1 TIMESTAMP(0) NOT NULL DEFAULT LOCALTIMESTAMP,tempel2 TIMESTAMP NOT NULL DEFAULT LOCALTIMESTAMP(0));INSERT INTO Ajatempel(tempel1, tempel2) VALUES (DEFAULT, DEFAULT);SELECT *FROM Ajatempel;Mõlemas väljas on ühesugune väärtus - rea lisamise kuupäev ja kellaaeg ilma sekundi murdosadeta. Veeru tempel1 korral on see saavutatud veeru tasemel deklareeritud kitsendusega, mis ütleb, et veerus sekundi murdosa ei registreerita.Veeru tempel2 korral on see saavutatud vaikimisi väärtuse leidmise kaudu. Vaikimisi väärtusena registreeritud väärtuse saab teatavasti üle kirjutada.UPDATE Ajatempel SET tempel2=LOCALTIMESTAMP;Nüüd on veerus tempel2 ka sekundi murdosad. Selles mõttes on veeru tempel1 korral kasutatud lahendus parem.Ajatempli tüüpi veeru täpsuse muutmiseks on lause: ALTER TABLE Ajatempel ALTER COLUMN tempel2 SET DATA TYPE timestamp(0);Kui sekundi murdosasid pole vaja registreerida, siis ongi parim lahendus selline, kus sekundi murdosade arvu piiratakse nii veeru tüübi kui ka vaikimisi väärtuse deklareerimisel.Kui kasutan modelleerimiseks ja SQL koodi genereerimiseks Enterprise Architect 12 või 16 modelleerimisvahendeid, siis saan seal PostgreSQL andmebaasi disaini mudelis määrata TIMESTAMP tüüpi veeru korral pikkuse (length) 0, kuid vaikimisi kasutatavate koodi genereerimise mallide korral sellega koodi genereerimisel ei arvestata. **Märksõnad:** sekundi murdosa ## Küsimus: Kuidas saab PostgreSQLis ühe lausega lisada tabelisse puuduvad read ja uuendada olemasolevaid ridu? **Vastus:** Sellist operatsiooni tuntakse ka nime all upsert (kombinatsioon INSERT ja UPDATE operatsiooniks).Selle realiseerimiseks saab PostgreSQLis kasutada INSERT ... ON CONFLICT lauset. Alates PostgreSQL 15 saab selleks kasutada ka MERGE lauset, mis võimaldab ühte lausesse kombineerida INSERT, UPDATE ja DELETE lause. Seda lauset kirjeldab ka SQL standard. Oracles on see lause ammu olemas. Näiteks, kui ülesandeks on lisada tabelisse Salary töötajad (tabelist Emp), kes on seal registreerimata ja uuendada (tabeli Emp põhjal) nende töötajate palku, kes seal on registreeritud, siis kui enne tuli PostgreSQLis kasutada sellist lausetINSERT INTO Salary (employee_id, sal)SELECT empno, sal FROM EmpON CONFLICT (employee_id) DO UPDATESET sal = EXCLUDED.sal;, saab tänu MERGE lausele ka nii.MERGE INTO Salary SUSING Emp EON (E.empno=S.employee_id)WHEN MATCHED THEN UPDATE SET sal = E.salWHEN NOT MATCHED THEN INSERT (employee_id, sal)VALUES (E.empno, E.sal);PostgreSQLi MERGE lause realisatsiooni probleemiks on, et kui samaaegselt MERGE lausega toimub INSERT lauseid, siis MERGE ei pruugi seda märgata, teeb ka ise INSERT ja tulemuseks unikaalsuse viga. ON CONFLICT kasutamise korral on tagatud, et toimub kas INSERT või UPDATE ja unikaalsuse viga ei teki. **Märksõnad:** upsert, merge ## Küsimus: Kuidas saaks vaadata olemasoleva PostgreSQL andmebaasi tabelite kirjeldust diagrammina? **Vastus:** Kui Teil on andmete modelleerimise CASE vahend, siis see võib toetada pöördprojekteerimist (reverse engineering) olemasolevast andmebaasist.Leidub ka eraldi andmebaaside haldusvahendeid, mis sellist funktsionaalsust pakuvad. Tõstan esile: DBVisualizer DBeaver pgAdmin Igaühe kohta on vastusele lisatud vähemalt üks ekraanipilt.Kõigi puhul on probleemiks, et visualiseerimise tulemuses ei näidata UNIQUE kitsendusi, CHECK kitsendusi, indekseid, kitsenduste ja indeksite nimesid.DBVisualizeris ei näe lisaks ka NOT NULL kitsendusi. Samuti ei saa seal teha eraldi diagramme andmebaaside erinevate alamosade kohta. DBeaveris on eraldi diagrammide loomine võimalik (Project => ER Diagrams). Looge kõigepealt tühi diagramm ja lohistage (drag and drop) seejärel sinna valik tabelitest. Täpselt nagu kontseptuaalse andmemudeli puhul võiks iga registri kohta luua eraldi diagrammid.DBeaveris on võimalik peita diagrammil osade, kuid mitte kõikide tabelite veerud. Selleks tuleb valida tabelit esitav kast ja parempoolse hiireklahvi alt avanevast menüüst valida Show Attributes => Selected Entity => None. Nii saate registri kohta käival diagrammil peita registrisse mittekuuluvate tabelite seosed, näidates samas registrisse kuuluvate tabelite seoseid teiste registrite tabelitega.Vaadake SIIT videot DBeaveris selliste diagrammide loomise kohta.pgAdmin (vähemalt 4.5.6) vahendisse on lisatud Generate ERD funktsionaalsus. Paraku on kõik tabelid ühel diagrammil. Samuti ei näe NOT NULL kitsendusi.Veel üks võimalus on kasutada pgModeler tarkvara, millel on pöördprojekteerimise võimekus. See vahend on mõeldud PostgreSQL andmebaasi disaini mudelite loomiseks. Veel üks võimalus on kasutada Oracle SQL Developer Data Modeler tarkvara, mida saab Oracle kodulehelt tasuta alla laadida. Tarkvara on tasuta, kuid allalaadimiseks on vajalik ennast eelnevalt kodulehel registreerida.  See vahend on eeskätt mõeldud Oracle andmebaasi disaini mudelite loomiseks. Esitan järgnevalt PostgreSQLiga koos kasutamise juhendi. Laadida alla Oracle SQL Developer Data Modeler. Installeerimiseks tuleb allalaetud fail lahti pakkida. Laadida SIIT alla JDBC draiver (jar fail). Tuleb valida kõige uuem versioon Java 8 jaoks. Kui ei kasuta ülikooli Wifit, siis luua FortiClient VPN ühendus, sest muidu ei saa ülikooli serveris oleva PostgreSQLiga ühendust luua. Käivitada Data Modeler. Valida Tools => Preferences => Data Modeler => Third Party JDBC Drivers Vajutada rohelise pluss märgiga nupule ja lisada viide eelnevalt allalaetud jar failile. Valida File => Import => Data Dictionary Lisada uus ühendus: Name: Ise valida (lubatud märgid: tähed, numbrid, @, _, -) Database Type: JDBC Username: serveri kasutajanimi (t+matrikli number) Password: serveri parool (saatsite konto küsimisel meiliga) JDBC URL: jdbc:postgresql://apex2.ttu.ee/siia_andmebaasi_nimi Driver Class: org.postgresql.Driver Vajutada nupule Test ja kui akna vasakusse alaserva ilmub teade Success, siis vajutada nupule Connect. Valida viisardis Next ja järgmisel sammul valida skeem(id), milles olevate tabelite kirjeldus soovitakse importida. Kui Te ise andmebaasis skeeme ei loonud, siis vaikimisi pandi skeemiobjektid skeemi public. Valida viisardis Next ja valida imporditavad tabelid. Lisaks baastabelitele saab valida ka vaateid. Diagrammil on vaated teistsuguse välimusega, näha on veergude nimed ja nende järjekord. Vaikimisi kuvatakse kõiki tabeleid ühel diagrammil ja tulemus ei ole hästi jälgitav (vt lisatud faili Data_modeler_suur_diagramm). Iga registri kohta eraldi diagrammi loomiseks saab luua alamvaateid (subview). Iga registri kohta luua vähemalt üks eraldi alamvaade ja lohistada igale alamvaatele ainult selle konteksits huvipakkuvad tabelid (vt lisatud faili Data_modeler_vaike_diagramm). Probleemiks on, et kui tabeli kirjeldus peaks olema erinevatel diagrammidel, siis selle tabeli kirjeldust dubleeritakse erinevates alamvaadetes. ## Küsimus: Kuidas sisestada phpPgAdmin programmi graafilise kasutajaliidese kaudu tekstilisse veergu NULL'i? **Vastus:** Vastava veeru juures on märkeruut NULL, mis tuleb märgistada (vt lisatud pilti). Vastasel juhul, kui jätta kirjelduse veerg täitmata, lisatakse veergu tühi string. SQLis üldiselt ja PostgreSQLis spetsiifiliselt on NULL (märgend, mis tähistab väärtuse puudumist) ja tühi string (lühikene tekstiline väärtus) kaks ise asja. Ühtlasi on see näide, kuidas andmebaasi kitsendused aitavad hoida andmeid korrastatumalt. Kui veerul kirjeldus ei oleks CHECK kitsendust, mis keelab veerus tühja stringi ja tühimärkidest koosnevad stringid, siis phpPgAdmini kaudu andmeid sisestades võiks mõnede laudade kirjeldus olla NULL, mõnedel aga ''. See omakorda muudaks hiljem keerulisemaks näiteks päringu, mis otsib puuduvate kirjeldustega laudu.SELECT * FROM Laud WHERE kirjeldus IS NULL OR kirjeldus='';vsSELECT * FROM Laud WHERE kirjeldus IS NULL; **Märksõnad:** PostgreSQL, phpPgAdmin, graafiline kasutajaliides, tühi string, NULL, CHECK kitsendus ## Küsimus: Kuidas teha kindlaks, kas PostgreSQL andmebaasisüsteem viib läbi automaatset prügikoristust? **Vastus:** Prügikoristus on vajalik, sest PostgreSQL kasutab multiversioon konkurentsjuhtimist (multiversion concurrency control), mis tähendab, et rea lugemine ei takista samal ajal selle sama rea muutmist ning rea muutmine ei takista samal ajal selle rea lugemist. See eeldab rea muutmisel või kustutamisel selle vana versiooni säilitamist andmebaasisüsteemi poolt. Vana versioon tuleb säilitada kuni leidub mõni tehing, mis võib vajada selle lugemist. Kui selliseid tehinguid enam ei ole, siis tuleks ridade vanad versioonid kettalt füüsiliselt kustutada ja seda teebki prügikoristus. Prügikoristust saab algatada käsitsi VACUUM lausega. Lisaks saab sisse lülitada automaatse prügikoristuse. Prügikoristusega koos saab ka värskendada andmebaasi statistikat. Andmebaasi statistika annab andmebaasisüsteemile infot andmebaasis olevate andmete kohta (nt kui palju ridu on tabelis) ja seda on andmebaasisüsteemil vaja, et koostada võimalikult täpseid täitmisplaane. Seega peaks statistika olema võimalikult täpne ja ajakohane.Üks võimalus automaatse prügikoristuse toimimise kontrollimiseks on teha päring süsteemikataloogi tabeli põhjal.SELECT name, setting, short_descFROM pg_settingsWHERE name LIKE 'autovacuum%' ORname='track_counts'ORDER BY name;Kui autovacuum=on ja track_counts=on, siis on automaatne prügikoristus serveris sisse lülitatud. autovacuum_vacuum_threshold - minimaalne muudetud või kustutatud ridade arv, mis käivitab tabeli automaatse prügikoristuse. Vaikimisi 50. autovacuum_vacuum_insert_threshold - minimaalne lisatud ridade arv, mis käivitab tabeli automaatse prügikoristuse. Vaikimisi 1000. autovacuum_analyze_threshold - minimaalne lisatud, muudetud või kustutatud ridade arv, mis käivitab tabeli statistika automaatse värskendamise. Vaikimisi 50. Rohkem infot juhtparameetrite kohta on SIIN.Järgnev päring leiab iga kasutaja skeemis oleva tabeli kohta, millal viimati selle prügi koristati või statistikat värskendati (käsitsi või automaatselt).SELECTschemaname, relname,last_vacuum, last_autovacuum,vacuum_count, autovacuum_count,last_analyze, last_autoanalyze,analyze_count, autoanalyze_countFROM pg_stat_user_tablesORDER BY schemaname, relname; **Märksõnad:** MVCC, multiversioon konkurentsjuhtimine, autovacuum ## Küsimus: Kui muuta PostgreSQL tabeli FILLFACTOR omaduse väärtust, siis kuidas see mõjutab olemasolevaid tabeli plokke? **Vastus:** FILLFACTOR parameetri väärtus määrab kui palju jäetakse tabeli plokkidesse vaba ruumi, et samasse plokki mahuks ära ka UPDATE lausete tulemusena tekkivad ridade uusversioonid. Tabelite puhul on FILLFACTOR parameetri vaikimisi väärtus 100. See tähendab, et tabeli plokid pannakse INSERT lausete tulemusel lisanduvaid ridu täiesti täis ja mingit vaba ruumi plokkidesse ei jäeta. Seega, kui UPDATE lausega muudetakse plokis olevat rida, siis rea uusversioon pannakse teise plokki.Kui näiteks määrata, et FILLFACTOR on 90, siis jäetakse plokki 10% vaba ruumi. Kui plokk on 90% ulatuses ridadega täidetud, siis INSERT lausetega lisanduvaid ridu sinna plokki enam ei lisata. Kui plokis olevat rida UPDATE lausega muudetakse, siis tekib reast uus versioon ja plokis on ruumi, et see panna sellesse samasse plokki.FILLFACTOR parameetri väärtust saab muuta ka olemasolevatel tabelitel.ALTER TABLE Tellimus SET (fillfactor = 90);Sellisel juhul hakkab see mõjutama uusi tabeli plokke, kuid ei mõjuta olemasolevaid. Seega on loogiline, et olemasolevate plokkide mõjutamiseks tuleb need ümberkorraldada.Selleks peaks käivitama VACUUM FULL lause, mille tulemusena kirjutatakse kogu tabeli sisu uude andmefaili.  Mida rohkem on tabelis andmeid, seda rohkem võtab see aega. Samuti lukustab see lause tabeli eksklusiivselt, st ükski teine transaktsioon ei saa tabelit samal ajal kasutada.VACUUM FULL Tellimus;Alternatiiviks on kasutada laiendust pg_repack, mille kasutamise korral tabelit eksklusiivselt ei lukustata. ## Küsimus: Kust võiks saada infot PostgreSQL funktsioonide testimise kohta? **Vastus:** Mõned mõtted sellel teemal on selle lõputöö jaotises 4.2.4. Seal kirjutatakse trigerite testimisest. Samas, nii nagu triger on ka funktsioon andmebaasis talletatud ja andmebaasisüsteemi käivitatav kood. Kui trigeri puhul on vaja testimiseks teha andmemuudatusi otse tabelites, siis funktsioonide puhul tuleks katsetada funktsioonide väljakutseid (SELECT laused) erinevate argumentidega. Kindlasti peaks testima seda, kuidas funktsioonid toimivad olukorras, kui nende kaudu üritatakse samaaegselt muuta ühtesid ja samu või omavahel seotud andmeelemente. ## Küsimus: Käivitan läbi psqli PostgreSQL andmebaasis CREATE TABLE lauseid. Saan ühe lause peale veateate: ERROR: syntax error at or near "CONSTRAINT" LINE 29: SET CONSTRAINT FK_Isik_Riik FOREIGN KEY (isikukoodi_riik) RE... Samas selles lauses ei ole SET CONSTRAINT fraasi. Milles on viga ja kuidas seda parandada? **Vastus:** Vea põhjus on CREATE TABLE lauses olevas tabeldusmärgis. See probleem esines kuni PostgreSQL 14 (kaasa arvatud). PostgreSQL 15 see probleem lahendati. Näiteks saan sellise veateate, kui käivitan lause tabeli C loomiseks (kogu katsetuse skript on küsimusele lisatud failis). 1.CREATE TABLE C(c_id INTEGER PRIMARY KEY, 2.    a_id INTEGER NOT NULL, 3.    b_id INTEGER NOT NULL, 4.    CONSTRAINT ak_c UNIQUE (a_id, b_id), 5.    CONSTRAINT fk_c_a FOREIGN KEY (a_id) REFERENCES A(a_id) ON DELETE No Action ON UPDATE Cascade, 6.    CONSTRAINT fk_c_b FOREIGN KEY (b_id) REFERENCES B(b_id) ON DELETE No Action ON UPDATE Cascade 7.);Veateade: ERROR: syntax error at or near "CONSTRAINT" LINE 6: SET CONSTRAINT fk_c_b FOREIGN KEY (b_id) REFERENCES B(b_id) ... Viga tekib sellest, et psql ei saa mõnikord tabeldusmärkidega hakkama. Reas nr 5 on võtmesõna UPDATE. Sellele järgneb rea nr 6 alguses tabeldusmärk. See paneb psqli arvama, et UPDATE on eraldi lause. Kuidas seda probleemi lahendada? Kustutage skriptist enne käivitamist tabeldusmärgid (tekstiredaktoris Search and Replace funktsioon). Käivitage skripti pgAdminis (seal seda probleemi ei ole). Panete (näiteks WinSCP programmi abil) skriptifaili apex2.ttu.ee serveris enda kodukataloogi (/home/kasutajanimi - satute sinna sisselogimisel). Seejärel käivitate shelli promptist selle skripti üldise käsuga: psql -f skriptifaili nimi andmebaasi nimi, kus soovite skripti käivitada Näiteks järgmine käsk käivitab failis DDL_PostgreSQL.sql olevad laused andmebaasis proov. psql -f DDL_PostgreSQL.sql proov **Märksõnad:** tab ## Küsimus: Käivitan PostgreSQLis funktsiooni, kuid seda ei täideta, sest ei leita funktsioonis viidatud tabelit. Mis on viga ja kuidas seda lahendada? Näide: Lõin andmebaasis funktsiooni f_on_juhataja SELECT f_on_juhataja(p_kasutajanimi:='joy.hawkins@geekosis.name', p_parool:='Boss'); ERROR: relation "isik" does not exist LINE 2: FROM isik INNER JOIN tootaja ON isik.isik_id = tootaja.isik_... **Vastus:** Kirjutasite funktsiooni loomise lauses: SET search_path = 'public, pg_temp' Tekst, mis on apostroofide e ülakomade vahel, on PostgreSQLi jaoks kokku üks skeemi nimi. PostgreSQL hakkas otsima sellise nimega skeemist tabelit Isik. Kuna sellist skeemi andmebaasis ei ole, siis ei leitud ka tabelit. Õige on kirjutada otsingutee ilma ülakomadeta: SET search_path = public, pg_temp Otsingutee on vajalik, et SECURITY DEFINER funktsioon oleks turvaline. ## Küsimus: Käivitasin PostgreSQLis skripti/päringu/andmemuudatuse, mis "jooksis kinni". Nüüd töötab andmebaasisüsteem aeglaselt ning protsess on lukustanud tabeli/vaate/andmebaasi, mille tulemusena ei saa ma seda muuta ega kustutada. Kuidas "rippuma jäänud" PostgreSQL kasutamise sessioonidest ja nendes algatatud ressursse blokeerivates serveriprotsessidest lahti saada? **Vastus:** Lahendust kirjeldatakse siin. Kokkuvõtlikult: Tuleb leida konkreetse andmebaasiga seotud sessioonid e seansid. Järgneva päringu võite käivitada tegelikult mistahes PostgreSQLi andmebaasis - st kui oma andmebaasis päringu käivitumisel jääb see toppama, siis ühenduge mõne teise andmebaasi külge. SELECT * FROM pg_stat_activity WHERE datname='andmebaasi nimi väiketähtedega'; Katkesta serveriprotsess ja lõpeta selle algatanud sessioon. SELECT pg_terminate_backend(pid);Kõige selle automatiseerimiseks võib psqlis käivitada järgneva skripti, asendades eelnevalt t990999 selle andmebaasi nimega, kus on kinni jooksnud päring.SELECT format('SELECT pg_terminate_backend(%1$s)', pid) AS statementsFROM pg_stat_activityWHERE datname='t990999' \gexecSkript koostab päringu tulemuse põhjal format funktsiooni kasutades dünaamiliselt SQL laused ja käivitab need automaatselt gexec käsu abil. ## Küsimus: Loon PostgreSQLis uue andmebaasi, kuid selles on kellegi teise loodud tabelid, domeenid või muud andmebaasiobjektid? Miks see nii on ja mida teha? **Vastus:** PostgreSQLis luuakse uus andmebaas tehes koopia mallandmebaasist (template1). Ülikasutaja õigustes kasutaja saab template1 andmebaasi muuta. Kõik sellesse lisatud andmebaasiobjektid tekivad peale lisamist selle malli põhjal loodud andmebaasidesse.Palun ärge lisage oma andmebaasiobjekte template1 andmebaasi! Kui olete seda kogemata teinud, siis kustutage need sealt. Kui avastate peale andmebaasi loomist enda andmebaasist kellegi teise loodud andmebaasiobjektid, siis tuleb need kustutada.Järgnevad käsud saab käivitada psqlis (pgAdminis valige selleks andmebaas ja siis menüüst Tools=>PSQL Tool). Käsk 1: Kustuta kõik kasutajate skeemides olevad tabelid ja nendest sõltuvad andmebaasiobjektid (nt vaated, rutiinid, trigerid).SELECT format('DROP TABLE %1$I.%2$I CASCADE;', table_schema, table_name) AS statementsFROM INFORMATION_SCHEMA.tables AS t INNER JOIN INFORMATION_SCHEMA.schemata AS s ON t.table_schema=s.schema_nameWHERE schema_name='public' OR schema_owner<>'postgres'\gexecKäsk 2: Kustuta kõik kasutajate skeemides olevad domeenid.SELECT format('DROP DOMAIN %1$I.%2$I CASCADE;', domain_schema, domain_name) AS statementsFROM INFORMATION_SCHEMA.domains AS d INNER JOIN INFORMATION_SCHEMA.schemata AS s ON d.domain_schema=s.schema_nameWHERE schema_name='public' OR schema_owner<>'postgres'\gexecKäsk 3: Kustuta kõik kasutajate skeemid, v.a. public.SELECT format('DROP SCHEMA %1$I CASCADE;', schema_name) AS statementsFROM INFORMATION_SCHEMA.schemata AS sWHERE schema_name<>'public' AND schema_owner<>'postgres'\gexecgexec käsk võimaldab päringuga koostatud SQL laused automaatselt käivitada. **Märksõnad:** template1, skript, andmebaasiobjektide kustutamine ## Küsimus: Lõin andmebaasis tabeli, kus võtmeveeru puhul oleks tulnud selle väärtused süsteemil genereerida, kuid unustasin seda määrata. Lisasin tabelisse juba ridu. Kuidas see omadus tabelile tagantjärgi lisada? **Vastus:** Toon näite.CREATE TABLE Kasutaja_rolli_omamine (kasutaja_rolli_omamine_id INTEGER NOT NULL,kasutaja_id INTEGER NOT NULL,rolli_kood SMALLINT NOT NULL,alguse_aeg TIMESTAMP(0) NOT NULL,lopu_aeg TIMESTAMP(0) NOT NULL DEFAULT 'infinity',CONSTRAINT pk_kasutaja_rolli_omamine PRIMARY KEY (kasutaja_rolli_omamine_id),CONSTRAINT ak_kasutaja_rolli_omamine UNIQUE (kasutaja_id, rolli_kood, alguse_aeg));/*Loon tabeli.*/INSERT INTO Kasutaja_rolli_omamine (kasutaja_rolli_omamine_id, kasutaja_id, rolli_kood, alguse_aeg)VALUES (1, 1, 1, LOCALTIMESTAMP(0));/*Lisan tabelisse rea.*/Järgnev näide teeb andmebaasis muudatused, mis võtmeveeru puhul SERIAL notatsiooni kasutamise korral oleks tehtud automaatselt.CREATE SEQUENCE kasutaja_rolli_omamine_kasutaja_rolli_omamine_id_seq OWNED BY Kasutaja_rolli_omamine.kasutaja_rolli_omamine_id;/*Loon arvujada generaatori ning määran, et selle omanik on võtmeveerg. See tagab, et tabeli kustutamisel kustutatakse automaatselt ka arvujada generaator.Kasutan arvujada generaatori puhul nime mustrit <tabeli nimi>_<veeru nimi>_seq, mida PostgreSQL kasutab ka automaatselt loodud arvujada generaatorite puhul.*/ALTER TABLE Kasutaja_rolli_omamine ALTER COLUMN kasutaja_rolli_omamine_id SET DEFAULT nextval('kasutaja_rolli_omamine_kasutaja_rolli_omamine_id_seq');/*Määran võtmeveerule vaikimisi väärtuse, mis küsitakse nextval funktsiooniga arvujada generaatori poole pöördumisel.*/SELECT setval('kasutaja_rolli_omamine_kasutaja_rolli_omamine_id_seq', Max(kasutaja_rolli_omamine_id))FROM Kasutaja_rolli_omamine;/*Määran setval funktsiooni abil, milline on viimane arvujada generaatori väljastatav väärtus. Järgmine väljastatav väärtus on sellest arvujada generaatori sammu (vaikimisi 1) võrra suurem. See on vajalik, et rea lisamisel ei tekitaks uus genereeritud väärtus konflikti andmebaasis juba olemasoleva võtmeväärtusega. Oht on selles, et samal ajal võivad kasutajad lisada tabelisse lisada uusi ridu, mida see Max päring ei näe.*/Järgnev näide pakub alternatiivse lahenduse - määrab, et tabeli veerg on identiteedi veerg. Ka selle korral tekib automaatselt arvujada generaator, mis seotakse võtmeveeruga.DROP TABLE IF EXISTS Kasutaja_rolli_omamine;Loon tabeli uuesti ning lisan sinna rea.ALTER TABLE Kasutaja_rolli_omamine ALTER COLUMN kasutaja_rolli_omamine_id ADD GENERATED  ALWAYS AS IDENTITY (START WITH 2);/*GENERATED ALWAYS - isegi kui kasutaja lisab veergu ise väärtuse, siis seda ei arvestata.START WITH 2 - esimene väljastatud väärtus on 2 (sest väärtust 1 on tabelis kasutatud).*/Arvujada generaatorite loomine ning tabeli veeru identiteedi veeruks määramine on kirjeldatud SQL standardis. SERIAL notatsiooni kasutamine on PostgreSQL laiendus. **Märksõnad:** identiteedi veerg, serial notatsioon, arvujada generaator ## Küsimus: Lõin PostgreSQL andmebaasis protseduuri (CREATE PROCEDURE lause). Seda MS Accessi rakendusest välja kutsudes saan veateateid nagu: Error while preparing parameters. ERROR: ... is a procedure; Error while preparing parameters. Milles on viga ja mida selle parandamiseks ette võtta? **Vastus:** Protseduurid on PostgreSQLis väga uus asi (lisandusid PostgreSQL 11) ja vanemad draiveri versioonid neid ei toeta. Lahenduseks on asendada serveris protseduurid funktsioonidega või kasutada viimast draiveri versiooni. **Märksõnad:** protseduur, rutiin, funktsioon, ODBC, MS Access, protseduuri väljakutse, VBA ## Küsimus: Miks kasutab PostgreSQL unikaalsuse kitsenduse jõustamiseks B+ puu (tasakaalustatud puu) indeksit, aga mitte hash (räsiväärtustel põhinevat) indeksit? **Vastus:** Võtmeveergudele loob PostgreSQL ja ka teised andmebaasisüsteemid automaatselt B+ puu (B+ tree) indeksi (Oracle, MySQL, MS SQL Server). MySQLis indekseeritakse automaatselt ka välisvõtmeid.Lugege siit väga head ülevaadet hash indeksitest PostgreSQLis. Mõned järeldused, mida see artikkel tegi eksperimentide põhjal. Hash indeks on B+ puu indeksist andmemahult väiksem. Hash indeksi suurus ei kasva lineaarselt, vaid sammudena. Hash indeksi suurust ei mõjuta indekseeritavate väärtuste suurus. Hash indeksi suurust ei mõjuta see kui unikaalsed (selektiivsed) on indekseeritavas veerus olevad väärtused. Mis on hash indeksi probleemid?Kõigepealt hoiatas PostgreSQL pikka aega hash indeksite kasutamise eest, sest sellega kaasnesid tehnilised probleemid. Kuni PostgreSQL 9.6 oli dokumentatsioonis hoiatus:"Hash index operations are not presently WAL-logged, so hash indexes might need to be rebuilt with REINDEX after a database crash if there were unwritten changes. Also, changes to hash indexes are not replicated over streaming or file-based replication after the initial base backup, so they give wrong answers to queries that subsequently use them. For these reasons, hash index use is presently discouraged."Andmebaasisüsteemi uuemates versioonides on need probleemid lahendatud. Kuid ikkagi, miks mitte kasutada unikaalsuse kitsenduse toetuseks hash indeksit?Põhjus on selles, et tulenevalt indeksi ülesehituses saab süsteem seda indeksit kasutada ainult selliste otsingute toetuseks, kus kasutatakse võrdsuse kontrolli operaatorit (=).Tsitaat: "Hash indexes store a 32-bit hash code derived from the value of the indexed column. Hence, such indexes can only handle simple equality comparisons. The query planner will consider using a hash index whenever an indexed column is involved in a comparison using the equal operator:" (allikas)(PostgreSQLi) piirangud hash indeksile. Indeksit ei saa luua mitmele veerule (liitindeks). Kandidaatvõti võib olla liitvõti. Indeksit ei saa sorteerida. Indeksi alusel ei saa tabeli ridu ühekordselt sorteerida (cluster). Võtmeväärtuste järgi tabeli ridade sorteerimine võib olla kasulik. Indeksit ei saa kasutada vahemiku järgi otsingu teostamiseks. Võtmeväärtuste vahemiku järgi ridade otsimine on levinud operatsioon. Indeksi alusel ei saa sorteerimisoperatsiooni kiirendada. Võtmeväärtuse järgi sorteerimine on levinud operatsioon. Seda tüüpi indeksit ei saa luua unikaalse indeksina. Seda tüüpi indeksi puhul ei saa PostgreSQL täita päringut nii, et loeb ainult seda indeksit (index only scan) - ikka on vaja lugeda ka tabeliplokke. Sellise võimaluse kasutamise eelduseks on, et indeksis peavad olema väärtused indekseeritud veerust või need väärtused peavad olema indeksis olevate andmete alusel taastatavad. Hash indeksis on seevastu nende väärtuste räsid ning ei ole "maagilist" võtit ega funktsiooni, mille abil nendest tabelites olevad tegelikud väärtused taastada. Nendest piirangutest tulenevalt ei sobi hash indeks ka välisvõtme veerule loodavaks indeksiks. **Märksõnad:** räsiväärtus, räsi, indeks, indekseerimine, indeksi tüüp ## Küsimus: Miks mitte kasutada klassifikaatori tabeli, välisvõtme veeru ja sellel oleva välisvõtme kitsenduse asemel loendustüüpi veergu? **Vastus:** Sest see: vähendab lahenduse porditavust e ülekantavust, vähendab lahenduse paindlikkust,  suurendab keerukust, suurendab PostgreSQL näitel salvestusruumi kasutamist. Kirjutan järgnevalt sellest pikemalt. Kõik järgnevad näited ja väited põhinevad PostgreSQLil.Esitan väikese näite, et oleks paremini aru saada, millest jutt käib. Olgu meil andmebaas, kus on vaja registreerida teenuseid ja nende liike. Iga teenus on täpselt ühte liiki. Iga teenuse liik iseloomustab null või rohkemat teenust.Disain 1CREATE TABLE Teenuse_liik (teenuse_liik_kood SMALLINT,nimetus VARCHAR(50) NOT NULL,CONSTRAINT pk_teenuse_liik PRIMARY KEY (teenuse_liik_kood),CONSTRAINT ak_teenuse_liik UNIQUE (nimetus));INSERT INTO Teenuse_liik VALUES (1, 'Hooldus'), (2, 'Arendus');CREATE TABLE Teenus (teenuse_kood INTEGER,teenuse_liik_kood SMALLINT NOT NULL,CONSTRAINT pk_teenus PRIMARY KEY (teenuse_kood),CONSTRAINT fk_teenus_teenuse_liik FOREIGN KEY (teenuse_liik_kood) REFERENCES Teenuse_liik (teenuse_liik_kood) ON UPDATE CASCADE);Disain 2CREATE TYPE teenuse_liik AS ENUM ('Hooldus','Arendus');CREATE TABLE Teenus (teenuse_kood INTEGER,teenuse_liik teenuse_liik NOT NULL,CONSTRAINT pk_teenus PRIMARY KEY (teenuse_kood));Küsimus on, kas ja miks peaks eelistama disaini 1 disainile 2? Ülekantavus Loendustüübi loomise ja selle tüübi haldamise laused pole kirjeldatud SQL standardis. Seega üleminekul teisele andmebaasisüsteemile pole alust õigustatud ootuseks, et uues süsteemis oleks võimalik samasugune loendustüübi kasutamise lahendus. Paindlikkus Ka PostgreSQL enese dokumentatsioon ütleb, et loendustüüp on staatiliste väärtuste hulga jaoks. Küsimus on,  kas klassifikaatorite väärtuste hulk on ikkagi staatiline e ajas muutumatu. Elu näitab, et see väärtuste hulk siiski võib ajas muutuda. Need andmed muutuvad palju harvemini kui põhiandmed või tehinguandmed, kuid siiski muutuvad. Näiteks seisundiliikide hulk võib muutuda ettevõtte äriprotsesside ümberkujundamisel, teenuse- ja kaubaliikide hulk võib muutuda ettevõtte äristrateegia muutumisel ja lubatud soo tähiste hulk võib muutuda koos ühiskonna meelsuse ja seadusandluse muutumisega. Teisalt, kui keegi tahab teha loendustüüpi tõeväärtuste (TRUE ja FALSE) esitamiseks, siis see on vale tee, sest PostgreSQL toetab tüüpi BOOLEAN. Loendustüübist ei saa väärtust eemaldada. Loendustüübist väärtuse eemaldamiseks tuleb tüüp kustutada ja uuesti luua, kuid kui tüüp on tabeli veeru puhul kasutusel, siis see on keerukas migreerimise protsess. Klassifikaatori tabelist saab DELETE lausega kustutada klassifikaatori väärtused, mida pole ühegi olemi iseloomustamiseks kasutatud. Klassifikaatori tabelisse saab lisada veeru, mis näitab, kas väärtus on aktiivselt kasutusel või mitte. Muutes klassifikaatori väärtuse mitteaktiivseks, saab keelata selle kasutamise uute olemite iseloomustamisel, samas kui olemasolevaid andmeid see ei mõjuta. Kui mingit tüüpi klassifikaatori korral soovitakse hakata registreerima lisaandmeid (näiteks kirjeldus), siis disain 1 korral tuleb lisada klassifikaatori tabelisse uus veerg, kuid disain 2 korral tuleb luua uus tabel, kus dubleeritakse info loendustüüpi kuuluvate väärtuste tekstiliste nimetuste kohta. Loendustüübi kasutamise korral on klassifikaatori väärtuste tekstiliste nimetuste maksimaalne pikkus määratud PostgreSQL NAMEDATALEN juhtparameetri väärtusega, mis enamasti tähendab, et nimetus saab olla kuni 63 baiti pikk (sõltub serveri sätetest). Klassifikaatori tabelite korral saab vastavalt vajadusel lubada lühemaid nimetusi ja pikemaid nimetusi. Loendustüübi kasutamisel saab luua tüübi, milles olevate väärtuste tekstilised nimed on tühjad stringid või tühikutest koosnevad stringid (CREATE TYPE test AS ENUM ('', ' ', '  ');). Klassifikaatorite tabelite korral saab selliste nimetustega klassifikaatori väärtuste registreerimise CHECK kitsenduste abil keelata. Loendustüüpi kuuluvate väärtuste omavahelise võrdlemise aluseks olev järjekord (kas väärtus "A" on suurem või väiksem kui väärtus "B") on määratud tüübi loomisel esitatud väärtuste järjekorraga. Selle muutmiseks tuleb tüüp kustutada ja uuesti luua (kui tüüp on veeru puhul kasutusel, siis see on keerukas migreerimise protsess). Klassifikaatori tabeli lahenduse korral saab UPDATE lause abil muuta koode ja nimetusi (kui need on võrdluse aluseks) või lisada tabelisse eraldi veeru, milles olevad andmed määravad klassifikaatori väärtuste järjekorra. Loendustüüpi kuuluvaid väärtuseid esitavad tekstilised lipikud on ühes keeles. Kui soovida neid tõlkida, siis ei saa kasutada mitmekeelse sisu SQL-andmebaasis esitamise disainimustreid. Keerukus Kui osa klassifikaatoreid on realiseeritud tabelitena ja osa loendustüüpidena, siis on klassifikaatorite andmete esitamiseks kaks eraldi lahendust, ühe asemel. Uue klassifikaatori väärtuse lisamiseks tuleb disain 1 korral kasutada INSERT lauset ja disain 2 korral ALTER TYPE lauset. Klassifikaatori väärtuse tekstilise nimetuse muutmiseks tuleb disain 1 korral kasutada UPDATE lauset ja disain 2 korral ALTER TYPE lauset. Klassifikaatorite väärtuste nimekirja esitamiseks kasutajaliideses tuleb disain 1 korral teha päring andmebaasi põhiosast ja disain 2 korral teha päring süsteemikataloogist või kasutada funktsioone. SELECT enumlabel AS nimetusFROM pg_enum INNER JOIN pg_type ON pg_enum.enumtypid=pg_type.oidWHERE pg_type.typname='teenuse_liik'; SELECT unnest(enum_range(null::teenuse_liik)) AS nimetus; Eelnev tähendab omakorda, et klassifikaatori väärtuste haldamise tarkvarale ja klassifikaatorite väärtuseid lugevale tarkvarale on vaja anda senisest rohkem õiguseid (turvarisk). Salvestusruum PostgreSQL seab igale loendustüüpi kuuluva väärtuse esitusele (tekstilisele lipikule) vastavusse nelja baidi suuruse täisarvu, mida kasutatakse tabelis, kus viidatakse tüüpi kuuluvatele väärtustele. Teiste sõnadega, klassifikaatori väärtusele osutava viite salvestamiseks kulub neli baiti. Klassifikaatori tabelite korral saan näiteks määrata, et kood on tüüpi SMALLINT ja sellisel juhul kulub viite salvestamiseks kaks baiti. INSERT INTO Teenus (teenuse_kood, teenuse_liik) VALUES (1,'Hooldus'), (2, 'Hooldus');SELECT pg_column_size(teenuse_liik) AS suurus_baitidesFROM Teenus; Sama probleemi kirjeldatakse B. Karwini SQL antimustrite raamatus antimustris "Kirjelda väärtused veeru definitsioonis" (peatükk 11, "31  maitset"). Seal keskendutakse võimalike väärtuste kirjeldamisele CHECK kitsenduses, kuid mainitakse, et samasugused probleemid tekivad ka loendustüüpide kasutamisel. **Märksõnad:** klassifikaator, loendustüüp, enumeration type, enumeration, reference data ## Küsimus: Miks on PostgreSQLis kasulik kasutada DATE ja TIMESTAMP tüüpidesse kuuluvat spetsiaalväärtust 'infinity'? **Vastus:** PostgreSQLi DATE ja TIMESTAMP tüüpidesse kuuluvad spetsiaalväärtused 'infinity' (suurem kui kõik ülejäänud DATE/TIMESTAMP väärtused) ja '-infinity' (väiksem kui kõik ülejäänud DATE/TIMESTAMP väärtused).Need lihtsustavad päringute tegemist. Tabelis Kasutus_1 on kasutusel, mille lõpu aeg pole teada, lõpu aja väli tühi (seal väljas on NULL). CREATE TABLE Kasutus_1 (kasutus_1_id SERIAL,ruumi_nr INTEGER NOT NULL,alguse_aeg TIMESTAMP NOT NULL,lopu_aeg TIMESTAMP,CONSTRAINT pk_kasutus_1 PRIMARY KEY (kasutus_1_id),CONSTRAINT ak_kasutus_1 UNIQUE (ruumi_nr, alguse_aeg));INSERT INTO Kasutus_1 (ruumi_nr, alguse_aeg) VALUES (1, '2022-10-04 12:00'), (2, '2022-10-04 12:00');INSERT INTO Kasutus_1 (ruumi_nr, alguse_aeg, lopu_aeg) VALUES (1, '2021-11-04 12:00', '2021-11-04 14:00'), (3, '2021-11-04 12:00', '2028-11-04 12:00');Tabelis Kasutus_2 on kasutusel, mille lõpu aeg pole teada, lõpu aja väljas väärtus 'infinity'.CREATE TABLE Kasutus_2 (kasutus_2_id SERIAL,ruumi_nr INTEGER NOT NULL,alguse_aeg TIMESTAMP NOT NULL,lopu_aeg TIMESTAMP NOT NULL DEFAULT 'infinity',CONSTRAINT pk_kasutus_2 PRIMARY KEY (kasutus_2_id),CONSTRAINT ak_kasutus_2 UNIQUE (ruumi_nr, alguse_aeg));INSERT INTO Kasutus_2 (ruumi_nr, alguse_aeg) VALUES (1, '2022-10-04 12:00'), (2, '2022-10-04 12:00');INSERT INTO Kasutus_2 (ruumi_nr, alguse_aeg, lopu_aeg) VALUES (1, '2021-11-04 12:00', '2021-11-04 14:00'), (3, '2021-11-04 12:00', '2028-11-04 12:00');Leia hetkel toimuvad kasutused. Päring juhul kui lõpu aeg võib olla NULL.SELECT *FROM Kasutus_1WHERE (LOCALTIMESTAMP BETWEEN alguse_aeg AND lopu_aeg)OR (alguse_aeg<=LOCALTIMESTAMP AND lopu_aeg IS NULL);Päring juhul kui teadmata lõpu aega tähistab spetsiaalväärtus 'infinity'.SELECT *FROM Kasutus_2WHERE (LOCALTIMESTAMP BETWEEN alguse_aeg AND lopu_aeg); **Märksõnad:** PosgtreSQL, andmetüüp, andmetüübid, spetsiaalväärtus, spetsiaalväärtused, vaikimisi väärtus ## Küsimus: Millal võiks olla kasu baastabeli arvutatud veergudest? **Vastus:** Arvutatud veeru puhul arvutatakse väljas olev väärtus teiste samas reas olevate väärtuste puhul ja salvestatakse kettale.Sellistest veergudest võib olla kasu koondandmete päringute puhul.Toon näite PostgreSQL 16 põhjal.Ülesanne: Tellimuste andmebaasis on tellimused ja tellimuste read. Ülesandeks on leida iga kuu(+aasta) kohta, kus on tehtud mõni tellimus, millised kliendid on teinud selles kuus(+aastas) kõige suuremas mahus tellimusi.Andmebaasi kontseptuaalne struktuur: [Tellimus]-1-----------1..*-[Tellimuse_rida]Loon tabelid.CREATE TABLE Tellimus (tellimus_kood INTEGER NOT NULL,klient_id INTEGER NOT NULL,tellimuse_kp DATE NOT NULL,tellimuse_aasta SMALLINT GENERATED ALWAYS AS (extract(year FROM tellimuse_kp)) STORED NOT NULL,tellimuse_kuu SMALLINT GENERATED ALWAYS AS (extract(month FROM tellimuse_kp)) STORED NOT NULL,CONSTRAINT pk_tellimus PRIMARY KEY (tellimus_kood));CREATE TABLE Tellimuse_rida (tellimus_kood INTEGER NOT NULL,toode_id INTEGER NOT NULL,yhiku_hind INTEGER NOT NULL,kogus INTEGER NOT NULL,summa INTEGER GENERATED ALWAYS AS (kogus * yhiku_hind) STORED NOT NULL,CONSTRAINT pk_tellimuse_rida PRIMARY KEY (tellimus_kood, toode_id),CONSTRAINT fk_tellimuse_rida_tellimus FOREIGN KEY (tellimus_kood)REFERENCES Tellimus (tellimus_kood) ON DELETE CASCADE);Lisan testandmed.INSERT INTO Tellimus (tellimus_kood, klient_id, tellimuse_kp)SELECT generator AS tellimus_kood,floor(random() * (1_000 - 1 + 1) + 1)::int AS klient_id,'2015-01-01'::date + floor(random() * (current_date - '2015-01-01' + 1) + 1)::int AS tellimuse_kpFROM generate_series(1, 15_000) AS generator;INSERT INTO Tellimuse_rida (tellimus_kood, toode_id, yhiku_hind, kogus)SELECT floor(random() * (1_000 - 1 + 1) + 1)::int AS tellimus_kood,floor(random() * (2_000 - 1 + 1) + 1)::int AS toode_id,floor(random() * (1_000 - 1 + 1) + 1)::int AS yhiku_hind,floor(random() * (10_000 - 1 + 1) + 1)::int AS kogusFROM generate_series(1, 100_000) AS generatorON CONFLICT DO NOTHING;DELETE FROM Tellimus WHERE NOT EXISTS (SELECT *FROM Tellimuse_ridaWHERE Tellimus.tellimus_kood=Tellimuse_rida.tellimus_kood);ANALYZE;Katsetan kahte lahendust, millest kummagi puhul on kaks variatsiooni. Variant 1 korral arvutatakse päringus kasutatavad väärtused käigult. Variant 2 korral kasutatakse andmete registreerimisel välja arvutatud ja salvestatud väärtuseid. Töökiiruse leidmiseks kasutan EXPLAIN ANALYZE lauset.Lahendus 1, variant 1EXPLAIN ANALYZE WITH Tellimus_stats AS (SELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summaFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_stats AS TsWHERE summa=(SELECT Max(summa) AS mFROM Tellimus_stats AS Ts2WHERE Ts.aasta=Ts2.aastaAND Ts.kuu=Ts2.kuu);Lahendus 1, variant 2EXPLAIN ANALYZE WITH Tellimus_stats AS (SELECT tellimuse_aasta AS aasta,tellimuse_kuu AS kuu,klient_id, Sum(summa) AS summaFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_stats AS TsWHERE summa=(SELECT Max(summa) AS mFROM Tellimus_stats AS Ts2WHERE Ts.aasta=Ts2.aastaAND Ts.kuu=Ts2.kuu);Lahendus 2, variant 1EXPLAIN ANALYZE WITH Tellimus_stats AS (SELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summa,Rank() OVER (PARTITION BY extract(year FROM tellimuse_kp), extract(month FROM tellimuse_kp) ORDER BY Sum(yhiku_hind*kogus) DESC) AS asetusFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_statsWHERE asetus=1;Lahendus 2, variant 2EXPLAIN ANALYZE WITH Tellimus_stats AS (SELECT tellimuse_aasta AS aasta, tellimuse_kuu AS kuu, klient_id, Sum(summa) AS summa, Rank() OVER (PARTITION BY tellimuse_aasta, tellimuse_kuu ORDER BY Sum(summa) DESC) AS asetusFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_statsWHERE asetus=1;Töökiiruse tulemused:Lahendus 1, variant 1: 280 msLahendus 1, variant 2: 166 msLahendus 2, variant 1: 100 msLahendus 2, variant 2: 65 msAntud juhul parandavad arvutatud veerud päringute töökiirust. ## Küsimus: Millest alustada, kui sooviks õppida (PostgreSQLis) päringute optimeerimist? **Vastus:** Minu arvates võiks alustada sellest, et õppida kirjutama mitte-ebaefektiivseid päringuid (lihtsustamata tingimused, üleliigsete tabelite lugemine, samade andmete mitmekordne lugemine jne). Selleks, et detektiivina lausete aeglase täitmise põhjuste jälgi ajada, tuleb aru saada täitmisplaanis kasutatavatest operatsioonidest.   Päringute optimeerimisest üldiselt kirjutatakse SIIN.   Ebaefektiivsetest päringutest kirjutatakse SIIN (materjal "Andmebaasid I" kodulehel - kasutajanimi SIS2 ja parool SIS2).   PostgreSQL füüsilistes täitmisplaanides kajastuvad operatsioonid (lihtsad ja lühikesed seletused): https://www.vertabelo.com/blog/technical-articles/understanding-execution-plans-in-postgresql Erinevat tüüpi operatsioonid täitmisplaanides: https://pganalyze.com/docs/explain/scan-nodes https://pganalyze.com/docs/explain/join-nodes  https://pganalyze.com/docs/explain/other-nodes  https://use-the-index-luke.com/sql/explain-plan/postgresql/operations  https://www.cybertec-postgresql.com/en/join-strategies-and-performance-in-postgresql/ Veel märkmeid: https://gist.github.com/hgmnz/883144 Võimalikud vahendid tekstiliselt esitatud täitmisplaanide paremaks struktureerimiseks ja visualiseerimiseks: https://explain.depesz.com/  http://tatiyants.com/pev/#/plans  See vahend soovib sisendiks saada päringu täitmisplaani JSON formaadis. Seda saab andmebaasisüsteemilt küsida nii: EXPLAIN (FORMAT JSON) SELECT ...;   Seejärel soovitan tekitada endale isiklikku liivakasti andmebaasi 5-10 tabeliga, millest suurimas tehinguandmeid sisaldavas andmebaasis on vähemalt üks miljon rida sünteetilisi testandmeid. Kui edaspidi tekib küsimus, milline SQL lause lahendab kõige efektiivsemalt mõne ülesande, siis saab selle andmebaasi põhjal sõnastada ülesandele analoogilise ülesande ja teha katsetusi. SIIT leiab näiteid PostgreSQLi jaoks testandmete genereerimise kohta. Vihjeks võib öelda, et palju on abi PostgreSQL funktsioonist generate_series. ## Küsimus: Millised on PostgreSQLi eelised võrreldes MySQLiga (miks me ei kasuta MySQLi)? **Vastus:** MySQL on avatud lähtekoodiga, tasuta kogukonnaversiooniga, populaarne (populaarsem kui PostgreSQL) ja piisavalt suure võimaluste hulgaga paljudes IT süsteemides kasutamiseks. See on eriti populaarne veebirakendustes ja pakub väga head töökiirust kui andmebaasis on vaja teha palju samaaegseid päringuid (kuid ei ole samaaegseid andmemuudatusi). See kuulub avatud lähtekoodiga tarkvara pinusse (stack) akronüümiga LAMP, mis on veebirakenduste loomisel väga populaarne ja mida pakuvad paljud teenusepakkujad.Enamik vaatlejaid samas nõustub, et PostgreSQL (mis on samuti avatud lähtekoodiga, tasuta ja populaarne) pakub andmebaasi programmeerijatele rohkem võimalusi ja see on hea jõudlusega (parem kui MySQL) kui samal ajal on vaja teha nii keerukaid päringuid kui andmemuudatusi.Seega kasutame võimalusterohkemat (huvitavamat) süsteemi, millega võibolla olete varem vähem kokkupuutunud.Internetis on väljas 2012. aasta juunis Rob Conery poolt Norwegian Developers Conference konverentsil peetud ettekande salvestus. Ettekande esimesed 15 minutit demonstreerivad väga ilmekalt MySQLi puuduseid. SIIN on videos välja toodud puuduste jätkuarutelu. Soovitan vaadata kogu ettekannet, sest seal tutvustatakse mõningaid huvitavaid PostgreSQLi pakutavaid võimalusi. Alates 14:30 Multiversioon konkurentsjuhtimine. Alates 20:30 Tabelite loomine pärimise kaudu ja selle kasutamine suure tabeli sektsioonideks jagamiseks (praeguseks on PostgreSQLis ka realiseeritud tabelite sektsioonideks jagamise võimalus ilma, et arendaja peaks ilmutatult ise alamtabeleid looma ja pärimist kasutama). Alates 26:30 Foreign Data Wrapper (võimalus teha päringuid paljudest välistest andmeallikatest). Alates 29:30 Andmetüübid (näitena käsitleti timestamp with timezone tüüpi, massiivitüüpe, liittüüpide loomise võimalust). Alates 44:30 on kokkuvõtte PostgreSQLi eelistest - hind (PostgreSQL on tasuta; vaadake võrdluseks Oracle hinnapakkumist), jõudlus, salvestusruumi kokkuhoid, väljalasete sagedus, sobivus ettevõtte infosüsteemides kasutamiseks. Kas MySQLis on need võimalused olemas? MySQLis on kasutusel multiversioon konkurentsjuhtimine, kuid see on realiseeritud PostgreSQList erinevalt. MySQLis ei saa luua tabeleid pärimise kaudu. Nii PostgreSQL uuemad versioonid kui ka MySQL toetavad deklaratiivset tabeli sektsioonideks jagamist (st selleks pole tabelite pärimist vajagi). MySQLis ei saa kasutada väliste andmete pakendajaid. MySQLis saab kasutada FEDERATED salvestusmootorit, mis võimaldab kasutada MySQL andmebaasis andmeid, mis on mõnes teises MySQL andmebaasis. Kasutamaks MySQLis mõne teise andmebaasisüsteemi andmebaasis olevaid andmeid tuleb kasutada tasulisi ja standardiseerimata erilahendusi. MySQLis ei ole andmetüüpi timestamp with time zone ja ajavöönditega tegelemine on paras peavalu. MySQLis ei saa kasutada massiivitüüpe. MySQLis ei saa kasutajad ise uusi andmetüüpe luua. Kokkuvõttes tuleb tõdeda, et PostgreSQLi näol on tegemist andmebaasisüsteemiga, mis pakub Oracle ja Microsofti andmebaasisüsteemidele väärikat konkurentsi ning mida saab väga edukalt kasutada ka suurtes ettevõtte infosüsteemides ning riigi infosüsteemides.2017. aastal võrreldi staatilist koodi analüüsi kasutades PostgreSQL, MySQL ja Firebird andmebaasisüsteemide koodi kvaliteeti (st kui palju on koodis vigu). Kõigil nendel on avatud lähtekood, mis muudab sellise analüüsi võimalikuks. Võrdlust saab lugeda siit. Võrdluse tulemusena leiti, et PostgreSQL ja Firebird olid koodi kvaliteedilt üsna ühesugused, kuid MySQL oli neist mõlemast selles osas halvem. Võrdluse autor naljatas, et talle meeldis MySQL kõige rohkem, sest seal olid kõige huvitavamad vead. PostgreSQLi kasutab näiteks Skype. Veel üheks PostgreSQLi heaks omaduseks on laiendatavus - SIIT leiate ülevaate laiendustest, mida Skype kasutab/arendab.Siin on üks värskem MySQL ja PostgreSQL võimaluste võrdlus.Siin on veel üks artikkel, mis kõrvutab PostgreSQLi MySQLiga ja tõstab esile PostgreSQLi kasvavat populaarsust idufirmade tehtavates arendustes. Ja siin on kokkuvõte ühe PostgreSQL administraatori kogemustest MySQLiga. MySQLi puhul toob ta negatiivsena esile õiguste jagamist ja reliiside poliitikat ning tõstab positiivsest küljest esile MySQLi tiražeerimise võimalusi. Veel üks arutelu, millised on PostgreSQL ja MySQL eelised ning puudused võrreldes üksteisega. PostgreSQL populaarsuse näiteks on Lõpparuanne Siseministeeriumi haldusala IKT teenuste arendamine ja haldamise finantseerimise jätkusuutlikkus ning mõju siseturvalisuse tagamisele. Selle kohaselt kasutab enamik siseministeeriumi haldusala IKT teenustest sisemiselt PostgreSQL andmebaasisüsteemi. Siit leiate PostgreSQL ja MySQL põhiliste omaduste võrdluse.Stack Overflow 2023. aasta küsitlus näitas, et PostgreSQL on MySQList populaarsem andmebaasisüsteem nii kõigi vastajate kui professionaalsete arendajate hulgas (need on kaks esimest andmebaasisüsteemi). Seda imetletakse ja soovitakse kasutada rohkem kui MySQLi ning kasutatakse professionaalsete arendajate poolt rohkem kui MySQLi. ## Küsimus: Milliseid laiendusi (extension) saab PostgreSQL andmebaasi arendaja apex2.ttu.ee serveris kasutada? **Vastus:** apex2.ttu.ee serveris on PostgreSQL andmebaaside arendajatele tehtud kättesaadavaks kõik PostgreSQL installatsiooniga kaasa tulevad laiendused, st neid saab CREATE EXTENSION lausega andmebaasi lisada. Järgnevalt viidatakse mõnedele nendele laiendustele täpsemalt. btree_gist Vajalik selleks, et luua andmebaasis EXCLUDE kitsendusi, mis välistavad kattuvate väärtuste vahemiku registreerimiseks. citext Tekstitüüp, mis võimaldab tõstutundetut otsingut. cube Andmetüüp, millesse kuuluvad väärtused on mitmemõõtmelised andmekuubid. dblink Andmebaasist teiste PostgreSQL andmebaaside kasutamiseks. Seda kasutab pgApex. earthdistance Geograafiliste punktide vaheliste kauguste arvutamine. file_fdw Väliste andmete pakendaja andmebaasi välistes failides olevate andmete kasutamiseks. fuzzystrmatch Stringide e sõnade sarnasuse arvutamine. hstore Andmetüüp, millesse kuuluvad väärtused on võti‑väärtus paarid. ltree Andmetüüp hierarhiliste andmete jaoks. pageinspect Andmefailides olevate plokkide e lehekülgede inspekteerimine. pgcrypto Krüpteerimine ja räsiväärtuste arvutamine. Muuhulgas saab kasutada paroolide räsiväärtuste arvutamiseks sh soola kasutamiseks. pg_trgm Stringide sarnasuse määramine kasutades trigramme. postgres_fdw Andmebaasist teiste PostgreSQL andmebaaside kasutamiseks. tablefunc Risttabeli päringute võimaldamine. Pakutavate laienduste nimekirja koos lühikirjeldusega näeb süsteemikataloogi päringuga. Laiendus plpgsql installeeritakse andmebaasis automaatselt.SELECT * FROM pg_available_extensions ORDER BY name;Kui soovite kasutada veel mõnda laiendust, siis andke sellest palun teada õppejõule.PostgreSQL on mitmel viisil laiendatav süsteem. Esiteks on selle lähtekood avalik ning kõigil huvilistel on võimalus seda uurida ja muuta. Lisaks sellele on PostgreSQLi sisseehitatud võimalusi andmebaasisüsteemi funktsionaalsuse laiendamiseks nagu võimalus luua uusi protseduurseid keeli ja võimalus luua ning andmebaasi installeerida laiendusi (extension). Laiendus on kogum andmebaasiobjekte, mis on mõeldud mingi kindla ülesannete klassi lahendamiseks. Enamasti on nendeks andmebaasiobjektideks funktsioonid, operaatorid (iga operaatori taga on tegelikult mingi funktsioon; operaator pakub teistsuguse süntaksi selle poole pöördumiseks) ja andmetüübid. Laienduse andmebaasi installeerimisel (CREATE EXTENSION lausega) lisatakse vastavad objektid andmebaasi. PostgreSQL installatsiooniga tuleb kaasa hulk laiendusi, mille kasutamise võimaluse saab installeerija andmebaaside kasutajatele anda. Samas on laiendusi veel palju rohkem ning igaühel on võimalus nende arendamisel kaasa lüüa. PostgreSQL Extension Network (PGXN) on leht, kus paljud nendest on registreeritud. ## Küsimus: Milliseid täiendusi SQL standardisse tegi SQL:2023 ja millised nendest võimalustest on ka PostgreSQL'is (kuni versioonini 16) olemas? **Vastus:** 2023. aastal tuli peale pikka ootamist välja SQL standardi uus versioon - SQL:2023. Eelmine versioon oli SQL:2016 - nimes on viide aastale. SIIN on ülevaade mõningatest täiendustest võrreldes SQL:2016 standardi versiooniga. Põhilised täiendused on seotud JSON formaadis andmete toe täiendamisega ja omaduste graafi toe lisamisega, aga ka keele tuuma kasutatavuse parandamisega.PostgreSQL toetas juba varasemalt mitmeid standardi uude versiooni tehtud täiendusi ning ka PostgreSQL 16 (tuli välja 2023. aasta septembris) lisandus mõningaid standardi uude versiooni lisandunud võimalusi.PostgreSQL 16 lisandus võimalus kasutada loetavuse parandamiseks täisarve ja püsikomaarve esitavates literaalides alakriipse.SELECT *FROM EmpWHERE sal>1_000_000;Samuti lisandus PostgreSQL 16 võimalus esitada täisarvu tüüpi väärtuse literaali muus formaadis kui kümnendformaat (nt kuueteistkümnend formaadis).SELECT *FROM EmpWHERE sal>0xF4240;Eelnevad kaks on samaväärsed kui päring:SELECT *FROM EmpWHERE sal>1000000;Veenduge: SELECT cast(0xF4240 AS INTEGER);Samuti lisandus PostgreSQL 16 kokkuvõttefunktsioon ANY_VALUE. Leia sellised ametikohad, millel töötab vähemalt kaks töötajat. Väljasta ametikoha nimetus ja ühe sellisel ametikohal töötava töötaja kood.SELECT job, any_value(empno) AS üks_töötaja_sellise_ametigaFROM EmpGROUP BY jobHAVING Count(*)>1;Samuti saab nüüd kontrollida, kas tekstiline väärtus esitab JSON väärtust.WITH vaartused AS (VALUES ('{"menu": {  "id": "file",  "value": "File",  "popup": {    "menuitem": [      {"value": "New", "onclick": "CreateNewDoc()"},      {"value": "Open", "onclick": "OpenDoc()"},      {"value": "Close", "onclick": "CloseDoc()"}    ]  }}}'), ('<menu id="file" value="File">  <popup>    <menuitem value="New" onclick="CreateNewDoc()" />    <menuitem value="Open" onclick="OpenDoc()" />    <menuitem value="Close" onclick="CloseDoc()" />  </popup></menu>'))SELECT column1 AS vaartus, column1 IS JSON AS is_jsonFROM vaartused;PostgreSQL toetas juba varasemast selliseid SQL:2023 lisandunud võimalusi: võimalust deklareerida, et UNIQUE kitsenduse kontekstis käsitletakse NULLi väärtusena ja seega NULL=NULL e mittekohustuslik UNIQUE veerus võib olla maksimaalselt üks NULL, CREATE TABLE unik (vaartus INTEGER,CONSTRAINT uq_unik UNIQUE NULLS NOT DISTINCT (vaartus));INSERT INTO unik(vaartus) VALUES (NULL);INSERT INTO unik(vaartus) VALUES (NULL); --ebaõnnestub grupeerimise tulemuse sorteerimist veeru järgi, mida pole SELECT klauslis, SELECT deptno, Count(*) AS cntFROM Dept INNER JOIN Emp USING (deptno)GROUP BY deptnoORDER BY dname; funktsioone greatest ja least, SELECT greatest(1,2,3) AS suurim, least(1,2,3) AS vähim; funktsioone lpad ja rpad, SELECT lpad(cast(123 as varchar), 12, '*') ; funktsioone, mis kärbivad stringi algusest rohkem kui ühe märgi, SELECT ltrim('****123', '*'); väljapikkuse mittemääramist tekstilise veeru defineerimisel, CREATE TABLE T(a CHAR, b VARCHAR); lihtsustatud tsükli kontrollimise süntaksi rekursiivsete päringute puhul, JSON andmetüüpi (PostgreSQLis on tüübid JSON ja JSONB) (samas ei ole PostgreSQL 16-s SQL:2023-s ette nähtud võimalust deklareerida, et JSON väärtuses peavad olema unikaalsed võtmed), JSONB tüüpi väärtuste korral nende võrdlemist ning nende alusel sorteerimist ja grupeerimist. PostgreSQL tugi SQL standardile on dokumentatsioonis kirjeldatud lisas, kus eraldi tuuakse välja, millised standardis ettenähtud keele võimalused on andmebaasisüsteemi poolt toetatud ja millised on mittetoetatud .Kahjuks ei ole PostgreSQL 16 veel omaduste graafi tuge. ## Küsimus: Mis vahe on PostgreSQLis VARCHAR ja CHAR andmetüüpidel? **Vastus:** Kui CHAR(n) tüüpi veerus salvestatakse tekstiline väärtus, mis on lühem kui n märki, siis lisatakse salvestamisel väärtuse lõppu tühikud, et saavutada maksimaalne lubatud stringi pikkus. VARCHAR(n) tüüpi veeru korral seda ei tehta. PostgreSQL oskab paljude operatsioonide korral CHAR(n) tüüpi väärtuse lõppu lisatud tühikuid ignoreerida. Tühikuid ei ignoreerita stringi mustrile vastavuse kontrollimisel. Seega LIKE, ILIKE, SIMILAR TO ja regulaaravaldisele vastavuse kontrolli operaatorite kasutamisel tekitab CHAR(n) tüüpi veerg probleeme.Kuna CHAR(n) tüübi korral lisatakse stringi lõppu tühikuid, siis kulub sellisel juhul rohkem salvestusruumi. CHAR ja VARCHAR tüüpi veergudes olevate andmetega operatsioonide tegemisel ei ole märkimisväärset töökiiruse erinevust.Deklaratsioon CHAR on samaväärne kui deklaratsioon CHAR(1)Deklaratsioon VARCHAR on samaväärne kui deklaratsioon TEXTAinukene põhjus eelistada veeru tüübina CHAR(n) kasutamist VARCHAR(n) kasutamisele on anda andmebaasi skeemi kasutajale märku (vihjata), et selles veerus on oodatud ühesuguse pikkusega (n-märki) stringid. Näiteks veeru deklaratsioon riik_kood CHAR(3) võiks anda lugejale märku, et selles veerus on oodatud alati täpselt kolme märgi pikkused koodid.Samas sõltumata sellest, kas veerg riik_kood on CHAR(3) või VARCHAR(3) tüüpi, tuleb reegli "kood koosneb täpselt kolmest suurtähest" andmebaasis jõustamiseks luua täiendav CHECK kitsendus. Vastasel juhul saab registreerida koode nagu "123" "!?" "aa ".SIIN on katsetus ja koodinäited, mis eelnevate väidete paikapidavust illustreerivad. ## Küsimus: Mul on sellised ja sellised tabelid ning ma pean nende põhjal lahendama sellise ja sellise andmete otsimise ülesande. Milline oleks selle ülesande kõige parema jõudlusega lahendus? **Vastus:** Tuleb korraldada eksperiment ja erinevaid lahendusi katsetada. Kui Teil pole käepärast serverit, kus saate "liivakastis" mängida, siis isegi keskkonnas nagu DB Fiddle saab luua tabeleid, genereerida sinna mõõdukal hulgal testandmeid ja vaadata päringute täitmise kiirust. Töökiiruse eksperimentide tulemused võivad sõltuda ka kasutatavast andmebaasisüsteemi versioonist (st erinevates versioonides on tulemused erinevad, kuna vahepeal on muutunud andmebaasisüsteemi sisemised viisid päringute töötlemiseks ja täitmiseks).Kirjeldan kõigepealt üldist protsessi ja siis toon näite. Looge tabelid (ilma kasutaja-loodud indeksiteta, et kiirendada hiljem testandmete lisamist). Lisage väga vähe testandmeid (mõned kuni kümned read), et kõigepealt koostada võimalikud ülesande lahendusvariandid ja kontrollida, et need annavad õige tulemuse. Testandmed peaksid olema sellised, et kontrollida lahenduse õigsust ka piirjuhtudel. Koostage ja testige lahendusvariante. Genereerige mõõdukal hulgal testandmeid (kümned tuhanded kuni sajad tuhanded read). Lisage puuduvad indeksid, värskendage andmebaasi statistikat. Testige lahendusvariante. Kustutage testandmed, eemaldage kasutaja-loodud indeksid. Genereerige suurel hulgal testandmeid (miljonid read). See on vajalik, sest töökiiruse halvenemine ei pruugi toimuda koos ridade arvu kasvuga lineaarselt, vaid see võib toimuda eksponentsiaalselt. Lisage puuduvad indeksid, värskendage andmebaasi statistikat. Testige lahendusvariante. Järgnevalt toon konkreetse näite. Katsetus on tehtud kasutades PostgreSQL 16.Ülesanne: Tellimuste andmebaasis on tellimused ja tellimuste read. Ülesandeks on leida iga kuu(+aasta) kohta, kus on tehtud mõni tellimus, millised kliendid on teinud selles kuus(+aastas) kõige suuremas mahus tellimusi.Andmebaasi kontseptuaalne struktuur: [Tellimus]-1-----------1..*-[Tellimuse_rida]Samm 1CREATE TABLE Tellimus (tellimus_kood INTEGER NOT NULL,klient_id INTEGER NOT NULL,tellimuse_kp DATE NOT NULL,CONSTRAINT pk_tellimus PRIMARY KEY (tellimus_kood));CREATE TABLE Tellimuse_rida (tellimus_kood INTEGER NOT NULL,toode_id INTEGER NOT NULL,yhiku_hind INTEGER NOT NULL,kogus INTEGER NOT NULL,CONSTRAINT pk_tellimuse_rida PRIMARY KEY (tellimus_kood, toode_id),CONSTRAINT fk_tellimuse_rida_tellimus FOREIGN KEY (tellimus_kood)REFERENCES Tellimus (tellimus_kood) ON DELETE CASCADE);Välisvõtme veerule tellimus_kood pole eraldi indeksit vaja, sest see on primaarvõtmes esimene veerg ja primaarvõtme loomisel luuakse automaatselt indeks, kus see veerg on esimene veerg.Samm 2INSERT INTO Tellimus (tellimus_kood, klient_id, tellimuse_kp)VALUES (1, 1, '2023-10-08'),(2, 1, '2023-10-09'),(3, 2, '2023-10-09'),(4, 1, '2023-09-09'),(5, 2, '2023-09-11'),(6, 2, '2023-09-15'),(7, 3, '2023-09-15');INSERT INTO Tellimuse_rida (tellimus_kood, toode_id, yhiku_hind, kogus)VALUES (1, 1, 5, 5),(1, 2, 3, 6),(2, 1, 5, 4),(2, 2, 3, 2),(3, 3, 10, 2),(4, 3, 10, 5),(5, 1, 5, 1),(5, 2, 3, 1),(6, 5, 6, 7),(7, 4, 5, 10);Pange tähele, et ühe lausega saab lisada mitu rida. Tellimuse ridade lisamisel tekitan olukorra, et mitmel kliendil on ühes kuus kõige suurem tellimuste maht. Lahendused peavad leidma selle kuu jaoks kõik need kliendid.Samm 3LahendusvariandidLahendus 1Ühise tabeli avaldisega (Common Table Expression, CTE) leian iga kuu+aasta ning kliendi kombinatsiooni kohta tema tellimuste mahu.Põhipäringus jätan korreleeruvat alampäringut kasutades alles read, kus vaadeldava kuu+aasta korral on see maht kõige suurem.WITH Tellimus_stats AS (SELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summaFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_stats AS TsWHERE summa=(SELECT Max(summa) AS mFROM Tellimus_stats AS Ts2WHERE Ts.aasta=Ts2.aastaAND Ts.kuu=Ts2.kuu);Lahendus 2Ühise tabeli avaldisega (Common Table Expression, CTE) leian iga kuu+aasta ning kliendi kombinatsiooni kohta tema tellimuste mahu ning asetuse tellimuste mahtude pingereas vaadeldava kuu+aasta korral. Põhipäringus võtan välja read, kus asetus on esimene.WITH Tellimus_stats AS (SELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summa,Rank() OVER (PARTITION BY extract(year FROM tellimuse_kp), extract(month FROM tellimuse_kp) ORDER BY Sum(yhiku_hind*kogus) DESC) AS asetusFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_statsWHERE asetus=1;Lahendus 3Variatsioonina lahendusest 2 loon hetktõmmise e materialiseeritud vaate ning teen päringu selle vaate põhjal.CREATE MATERIALIZED VIEW Tellimus_stats ASSELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summa,Rank() OVER (PARTITION BY extract(year FROM tellimuse_kp), extract(month FROM tellimuse_kp) ORDER BY Sum(yhiku_hind*kogus) DESC) AS asetusFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id;SELECT aasta, kuu, klient_id, summaFROM Tellimus_statsWHERE asetus=1;Samm 4Genereerin testandmeid kasutades andmebaasisüsteemi pakutavaid võimalusi. Kirjutan täisarve loetavuse huvides alakriipse kasutades, mis on võimalik alates PostgreSQL 16.Genereerin 15 000 tellimust. klient_id on juhuslik täisarv vahemikus 1 ja 1 000 ning tellimuse kuupäev on  juhuslik kuupäev vahemikus 1. jaanuar 2015 ja tänane kuupäev (leitakse funktsiooniga CURRENT_DATE). SELLE FAILI lõpus on veel näiteid testandmete genereerimisest.INSERT INTO Tellimus (tellimus_kood, klient_id, tellimuse_kp)SELECT generator AS tellimus_kood, floor(random() * (1_000 - 1 + 1) + 1)::int AS klient_id,'2015-01-01'::date + floor(random() * (current_date - '2015-01-01' + 1) + 1)::int AS tellimuse_kpFROM generate_series(1, 15_000) AS generator;Genereerin 100 000 tellimuse rida. toode_id on juhuslik täisarv vahemikus 1 ja 2 000, ühiku hind on juhuslik täisarv vahemikus 1 ja 1 000 ning kogus on juhuslik täisarv vahemikus 1 ja 10 000. ON CONFLICT DO NOTHING on vajalik selleks, et juhul kui genereeritakse mitu rida, kus on sama tellimuse koodi ja toote id kombinatsioon, siis ei tekiks unikaalsuse rikkumise viga, vaid viga tekitanud rida lihtsalt ei lisata tabelisse ja jätkatakse tööd. Selle tulemusena tekib tabelisse vähem kui 100 000 tellimuse rida.INSERT INTO Tellimuse_rida (tellimus_kood, toode_id, yhiku_hind, kogus)SELECT floor(random() * (1_000 - 1 + 1) + 1)::int AS tellimus_kood,floor(random() * (2_000 - 1 + 1) + 1)::int AS toode_id,floor(random() * (1_000 - 1 + 1) + 1)::int AS yhiku_hind,floor(random() * (10_000 - 1 + 1) + 1)::int AS kogusFROM generate_series(1, 100_000) AS generatorON CONFLICT DO NOTHING;Eemaldan tellimused, millel pole ühtegi tellimuse rida. Kustutatakse kuni 5000 tellimust, e tellimusi jääb alles umbes 10 000.DELETE FROM Tellimus WHERE NOT EXISTS (SELECT *FROM Tellimuse_ridaWHERE Tellimus.tellimus_kood=Tellimuse_rida.tellimus_kood);Värskendan hetktõmmist.REFRESH MATERIALIZED VIEW Tellimus_stats;Samm 5Värskendan statistikat kasutades ANALYZE lauset.ANALYZE;Samm 6Töökiiruse testimiseks kasutan EXPLAIN ANALYZE lauset. Sellisel juhul lause täidetakse, ning ma näen lause täitmise plaani, plaani koostamise aega ja täitmiseks kulunud aega. Lause tulemusena leitud andmeid ei kuvata. Üldiselt võiks selliseid lauseid käivitada korduvalt ja leida aegade keskmise. Piirdun antud juhul ühe käivitamisega.See on EXPLAIN ANALYZE lause näide.EXPLAIN ANALYZE WITH Tellimus_stats AS (SELECT extract(year FROM tellimuse_kp) AS aasta,extract(month FROM tellimuse_kp) AS kuu,klient_id, Sum(yhiku_hind*kogus) AS summaFROM Tellimus INNER JOIN Tellimuse_rida USING (tellimus_kood)GROUP BY aasta, kuu, klient_id)SELECT aasta, kuu, klient_id, summaFROM Tellimus_stats AS TsWHERE summa=(SELECT Max(summa) AS mFROM Tellimus_stats AS Ts2WHERE Ts.aasta=Ts2.aastaAND Ts.kuu=Ts2.kuu);Tulemused mõõduka testandmete hulga korral.Lahendus 1: 295 msLahendus 2: 95 msLahendus 3: 0.3 ms Sinna tuleb juurde arvestada see, et hetktõmmise värskendamiseks kulus 90 ms. Kuid hetktõmmise kasutamise eelis tuleb sellest, et juhul kui kõige uuemaid andmeid ei pea arvestama, siis saab hetktõmmist värskendada teatud intervalli tagant (mitte koos iga andmemuudatusega) e asünkroonselt.Samm 7Kasutan testandmete kiireks kustutamiseks TRUNCATE lauset.TRUNCATE Tellimus CASCADE;Võrdluseks: DELETE lausega kustutades (DELETE FROM Tellimus;) kulub 185 ms, TRUNCATE lausega 8 ms.Samm 8Genereerin testandmeid nii, et tellimusi oleks umbes 1 miljon ja tellimuse ridu umbes 10 miljonit. Kuna osadele tellimustele ei pruugita tellimuse ridu genereerida, siis loon algul 1.5 miljonit tellimust ja kustutan tellimused, millele pole tellimuse ridu lisatud.Samm 9ANALYZE;Samm 10Uus katsetusLahendus 1: Peale tunniajalist töötamist katkestasin, sest tulemust ei olnud.Lahendus 2: 4837 msLahendus 3: 15 ms. Sinna tuleb juurde arvestada see, et hetktõmmise värskendamiseks kulus 4853 ms. Kuid hetktõmmise kasutamise eelis tuleb sellest, et juhul kui kõige uuemaid andmeid ei pea arvestama, siis saab hetktõmmist värskendada teatud intervalli tagant (mitte koos iga andmemuudatusega) e asünkroonselt.JäreldusedOptimaalseim on Lahendus 2. Juhul kui kõige uuemaid andmeid ei pea tulemuse arvutamisel arvestama, siis on optimaalseim Lahendus 3. Lahendus 1 näitas, et koos andmehulga kasvuga võib töökiirus halveneda mitte lineaarselt, vaid eksponentsiaalselt. ## Küsimus: PostgreSQL andmebaasisüsteemiga ei saa ühendust, sest aktiivsete klientide limiit on täis (too many clients). Milles võib olla põhjus ja kuidas probleemi lahendada? **Vastus:** Samaaegselt lubatud Postgresql kasutajate arvu on juba suurendatud 300-ni (vaikimisi arv on 100). Paraku juhtub aeg-ajalt, et ühe või teise serveri kasutaja tegevuse tulemusena genereeritakse nii palju ühendusi, et kogu ühenduste arv saab täis. PostgreSQL (10.1) korral oli sellisel juhul probleemide allikaks ühes andmebaasis olev riknenud väline tabel ja/või selle loomiseks vajalik laiendus. Selle tabeli põhjal päringut tehes loodi ühe ühenduse asemel nii palju ühendusi, et aktiivsete ühenduste limiit sai täis. Käivitades nimetatud andmebaasis lause: DROP EXTENSION IF EXISTS postgres_fdw CASCADE; ning seejärel uuesti ülesandes 5 oleva väliste tabelite loomise koodi, sai väliseid tabeleid probleemideta kasutada. Kui puutute sama probleemiga kokku oma andmebaasis, siis peaksite toimima sarnaselt - kustutage laiendus ja sellest sõltuvad objektid enda andmebaasist ning käivitage ülesande 5 kood uuesti. Kui põhjus pole Teis, vaid kelleski teises, siis aitab mulle kirja saatmine. Infoks: Päringuga (suvalises) andmebaasis: SELECT * FROM (SELECT count(*) AS used_connections FROM pg_stat_activity) q1, (SELECT setting::int AS res_for_super FROM pg_settings WHERE name=$$superuser_reserved_connections$$) q2, (SELECT setting::int AS max_connections FROM pg_settings WHERE name=$$max_connections$$) q3; leiate hetkel aktiivsete ühenduste arvu ja ühenduste maksimaalse arvu. Käsuga  ps ax | grep post shelli promptis näete hetkel PostgreSQLiga seotud protsesse. Kui seal mingi matriklinumber palju kordub, siis põhjuseks on just see paljude ühenduste genereerimine. Samuti palun kõikidel üliõpilastel töö lõppedes psqlist või pgAdminist välja logida, sest nagu eespool kirjas, ei ole samaaegsete ühenduste arv piiramatu ressurss! ## Küsimus: PostgreSQL andmebaasi varukoopia tegemisel pgAdmini programmiga esineb mul viga: pg_dump: server version: 16.0; pg_dump version: 15.5 pg_dump: aborting because of server version mismatch Mida teha? **Vastus:** See viga võib esineda ka tulevastes versioonides. Üldine põhjus on selles, et kasutatav pgAdmini versioon ei vasta kõige uuemale PostgreSQLi versioonile. Tüüpiliselt tuleb PostgreSQList välja uus põhiversioon igal sügisel (tavaliselt septembri lõpus või oktoobris). Üheks lahenduseks on installeerida pAdmini kõige viimane versioon, mis peab olema tulnud välja peale PostgreSQL uut versiooni ning suudab juba arvestada uue PostgreSQL versiooniga. Alternatiivselt saab loogilise varukoopia teha phpPgAdmin kaudu, valides andmebaasi ja klõpsates menüüs Export. Kui valida andmete esituse formaadiks "SQL", siis on tulemuseks INSERT laused. Paraku on need halvasti kirjutatud selles mõttes, et INSERT klauslis ei ole veergude nimesid. Teiste sõnadega sellised laused on tundlikud veergude järjekorra muutmise suhtes. Selliseid lauseid tuleks käsitsi täiendada. Veel üheks lahenduseks on kasutada varukoopia tegemiseks serveris olevat pg_dump utiliiti, käivitades selle shelli promptist. Järgnevalt kirjutan, kuidas seda teha. Loogilise varukoopia tegemine Logige PuTTY või mõne muu sarnase programmiga apex2.ttu.ee serverisse. Käivitage shelli promptist käsk, mille üldkuju on: pg_dump -C -f varukoopia_faili_nimi.sql andmebaasi_nimi_millest_tahan_varukoopiat Näiteks varukoopia andmebaasist scott: pg_dump -C -f scott_2023_11_07.sql scott C tähendab, et varukoopia failis on CREATE DATABASE lause. See tähendab, et varukoopiast andmebaasi taastamiseks ei tohi serveris sellise nimega andmebaasi olla - see luuakse taastamise alguses automaatselt. Soovitan kasutada varukoopia faili nimes andmebaasi nime ja varukoopia tegemise kuupäeva, et oleks selge, millest ja mis aja seisuga on varukoopia loodud ning et uus varukoopia vana üle ei kirjutaks. Fail sisaldab andmebaasi scott põhjal genereeritud SQL lauseid. Failis sisalduvad SQL laused andmebaasiobjektide loomiseks, õiguste jagamiseks ja andmete laadimiseks andmebaasi. See käsk tuleb käivitada shelli promptis (satute sinna kohe peale sisselogimist; see sama koht kus käivitate psql programmi), mitte psqlis. pg_dump nagu ka psql on PostgreSQLiga kaasa tulevad (abi)programmid. Logige WinSCP või muu sarnase failide haldamiseks mõeldud programmiga apex2.ttu.ee serverisse. Kasutajanimi ja parool on sama, mis PuTTY abil sisselogimisel. Sisselogimise järel satute oma kodukataloogi: /home/minu_kasutajanimi Loodud varukoopia fail on selles kataloogis. Tõmmake see fail enda arvutisse, sest kui näiteks serverarvutis ketas rikneb, siis ei ole riknenud kettale jäänud ja kättesaamatuks muutunud failidest hiljem taastamise juures abi. Tehke varukoopiate hoidmiseks enda arvutis eraldi kataloog. Varukoopia failis on andmete tabelisse lisamiseks vaikimisi COPY laused. See on andmete taastamiseks kõige kiirem lahendus. Kui soovite (näiteks dokumendi jaoks) saada andmete tabelisse lisamiseks INSERT lauseid, siis tuleb varukoopia tegemise käsku täiendada. Järgnev on konkreetse andmebaasi (scott) varundamise käsu näide: pg_dump -C --column-inserts -f scott_2023_11_07.sql scott Andmebaasi taastamine loogilisest varukoopiast Eeldused: Serveris pole sellise nimega andmebaasi, mille CREATE DATABASE lause on varukoopia faili alguses. Loogilise varukoopia fail on serverarvutis Teie kodukataloogis: /home/minu_kasutajanimi Logige PuTTY või mõne muu sarnase programmiga apex2.ttu.ee serverisse. Käivitage shelli promptist käsk, mille üldkuju on: psql -U minu_kasutajanimi -f varukoopia_faili_nimi.sql template1 Näiteks kasutaja erki taastab andmebaasi scott käsuga: psql -U erki -f scott_2023_11_07.sql template1 Vaadake SIIT videot loogilise varukoopia tegemise ning andmebaasi taastamise kohta. **Märksõnad:** loogiline varukoopia, tõmmis, damp, print ## Küsimus: PostgreSQLis NULL || tekstiline väärtus = NULL. Kuidas luua PostgreSQLis sarnane operaator MS Accessi stringide konkatenatsiooni operaatorile &, mille korral NULL & tekstiline väärtus = tekstiline väärtus? **Vastus:** Järgneva koodi võite käivitada oma andmebaasis ja see loob operaatori & mis käitub nii: NULL & tekstiline väärus = tekstiline väärtus NULL & NULL = tühi string CREATE FUNCTION textcat_coalesce(text, text) RETURNS text AS $$ SELECT coalesce($1,'') || coalesce($2,''); $$ LANGUAGE sql IMMUTABLE LEAKPROOF; COMMENT ON FUNCTION textcat_coalesce(text, text) IS 'Stringide konkatenatsiooni operaatorit & realiseeriv funktsioon. Tagab, et operatsiooni tulemus pole NULL.'; CREATE OPERATOR & ( LEFTARG = text, RIGHTARG = text, PROCEDURE = textcat_coalesce ); SELECT NULL || 'katsetus' AS tulemus; Tulemus:NULL SELECT NULL & 'katsetus' AS tulemus; Tulemus: katsetus NB! Alternatiiv sellise operaatori kasutamisele oleks tarvitada koos PostgreSQLi konkateneerimise operaatoriga (||) coalesce funktsiooni. coalesce funktsiooni pool pöördumisel võib ette anda mitu samatüübilist argumenti. Funktsioon tagastab vasakult lugedes esimese argumendi, mis ei ole NULL (või kui kõik argumendid on NULLid, siis tagastab NULLi). Seda funktsiooni saab kasutada NULLi asendamiseks konkreetse väärtusega. SELECT coalesce(NULL,'') || 'katsetus' AS tulemus; Tulemus: katsetus (sest kokku ühendatakse kaks väärtust - 'katsetus' ja '') Samuti võib kasutada concat_ws funktsiooni. SELECT concat_ws(' ', 'katsetus', NULL) AS tulemus; Tulemus: katsetus (sest funktsioon ignoreerib NULL argumente) ## Küsimus: PostgreSQLis saab luua/kasutada veergudeta (null veeruga) tabeleid. Miks ma peaksin tahtma sellist tabelit luua/kasutada? **Vastus:** PostgreSQLis saan luua baastabeli, kus on null veergu (aste on null) ja lisada sinna null või rohkem rida (tabeli võimsus on null või rohkem). CREATE TABLE on_avatud(); INSERT INTO on_avatud DEFAULT VALUES; Saan selliseid tabeleid kasutada tõeväärtustüüpi juhtparameetrite realiseerimiseks. Need on disainitaseme abitabelid, mis kontseptuaalses andmemudelis ei kajastu. SELECT Count(*) AS cnt FROM on_avatud; Kui süsteem on avatud, siis cnt>=1 Kui süsteem on suletud, siis cnt=0 Alates PostgreSQL 9.4 saab kirjutada SELECT lauseid (ilma DISTINCT operatsioonita), kus SELECT klauslis olev veergude hulk on tühihulk. Päringu tulemuseks olevas nimetus tabelis ei ole ühtegi veergu. SELECT FROM on_avatud; Kui süsteem on avatud, siis leitud ridade arv >=1 Kui süsteem on suletud, siis leitud ridade arv =0 Tühja SELECT klausliga päringuid saab kasutada jah/ei küsimuste formuleerimiseks. Kas osakonnas 10 on mõni töötaja? SELECT FROM Emp WHERE empno=10; Kui jah, siis leitud ridade arv >=1 Kui ei, siis leitud ridade arv =0 Erinevused relatsioonilisest mudelist. Ei saa luua nimega tuletatud tabeleid (vaateid, hetktõmmiseid), mille aste on null. Sellise tabeli võimsus võib olla ühest suurem. SQLis üldiselt peab tabelis olema vähemalt üks veerg. ## Küsimus: Teeme projekti PostgreSQLis ning mitmekesi. Millisesse andmebaasi tuleb panna rakenduse andmebaasiobjektid? Kuidas me üksteise tehtud PostgreSQL andmebaasidele ligi pääseme? **Vastus:** PostgreSQLis on apex2.ttu.ee serveris kõigil üliõpilastel ülikasutajate (superuser) õigused. Kõik üliõpilased pääsevad piiranguteta kõikidele serveris olevatele PostgreSQL andmebaasidele ligi ja saavad seal kõike teha. Andmebaasis ja skeemis võib olla erinevatele kasutajatele kuuluvaid andmebaasiobjekte. Projekti tegemiseks peate valima ühe rühmaliikme andmebaasi või võite ka teha täiesti eraldi andmebaasi. Kõik saate töötada sama andmebaasiga. ## Küsimus: Teen otsingusüsteemi ja pean toetama võimalust, et üks või mitu otsingutingimust tuleb päringus AND'idega kokku siduda? Millisel viisil oleks seda efektiivne teha? **Vastus:** Teen katsetuse PostgreSQL (15) andmebaasis, millel on järgnev kontseptuaalne struktuur.[Person]-1-----------0..*-[Health_care_visit]-0..*----------------1-[Facility]TabelisHealth_care_visit - 1 miljon ridaPerson - 70000 ridaFacility - 50000 ridaPäring ühe tabeli põhjal - kolm alternatiivset viisi päringutingimuste AND-idega sidumiseksEXPLAIN ANALYZE SELECT health_care_visit_idFROM Health_care_visitWHERE facility_id BETWEEN 1 AND 100INTERSECT  SELECT health_care_visit_idFROM Health_care_visitWHERE patient_id BETWEEN 47000 AND 55000;--90 msEXPLAIN ANALYZE SELECT health_care_visit_idFROM Health_care_visitWHERE facility_id BETWEEN 1 AND 100AND patient_id BETWEEN 47000 AND 55000;--2.5 msEXPLAIN ANALYZE SELECT health_care_visit_idFROM (SELECT health_care_visit_idFROM Health_care_visitWHERE facility_id BETWEEN 1 AND 100) AS a INNER JOIN(SELECT health_care_visit_idFROM Health_care_visitWHERE patient_id BETWEEN 47000 AND 55000) AS bUSING (health_care_visit_id);--6 msPäring mitme tabeli põhjal - kolm alternatiivset viisi päringutingimuste AND-idega sidumiseksEXPLAIN ANALYZE SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Facility USING (facility_id)INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idWHERE facility_name LIKE 'A%'AND last_name LIKE 'A%';--97 msEXPLAIN ANALYZE SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Facility USING (facility_id)WHERE facility_name LIKE 'A%'INTERSECT SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idWHERE last_name LIKE 'A%';--181 msEXPLAIN ANALYZE SELECT health_care_visit_idFROM (SELECT health_care_visit_idFROM Health_care_visit INNER JOIN Facility USING (facility_id)WHERE facility_name LIKE 'A%') AS a INNER JOIN (SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idWHERE last_name LIKE 'A%') AS b USING (health_care_visit_id);--91 msMõlemal juhul on INTERSECT kasutamine kõige aeglasemVaate kasutamine, et otsida ühe või mitme tingimuse järgiEXPLAIN ANALYZE SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Facility USING (facility_id)WHERE facility_name LIKE 'A%';--67 msCREATE VIEW v_hcv ASSELECT Health_care_visit.health_care_visit_id, facility_name, last_nameFROM Health_care_visit INNER JOIN Facility USING (facility_id)INNER JOIN Person ON Health_care_visit.patient_id=Person.party_id;EXPLAIN ANALYZE SELECT health_care_visit_idFROM v_hcvWHERE facility_name LIKE 'A%';--105 msKui otsisin ühe tingimuse järgi, siis päring vaate põhjal, mis ühendas mitut tabelit, oli aeglasem kui päring ainult nende tabelite põhjal, mida oli vaja päringule vastamiseks.EXPLAIN ANALYZE SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Facility USING (facility_id)WHERE facility_name LIKE 'A%'INTERSECT SELECT Health_care_visit.health_care_visit_idFROM Health_care_visit INNER JOIN Person ON Health_care_visit.patient_id=Person.party_idWHERE last_name LIKE 'A%';--181 msEXPLAIN ANALYZE SELECT health_care_visit_idFROM v_hcvWHERE facility_name LIKE 'A%'AND last_name LIKE 'A%';--95 msKui otsisin mitme tingimuse järgi, siis päring vaate põhjal, mis ühendas mitut tabelit, oli kiirem kui INTERSECTi kasutav päring otse tabelite põhjal. ## Küsimus: Üritan käivitada PostgreSQLis kasutaja-defineeritud funktsiooni, kuid saan vastuse, et sellist funktsiooni pole loodud. Mis võib olla põhjus? **Vastus:** Funktsiooni identifikaator e signatuur moodustub selle identifikaatorist ja sisendparameetritest. PostgreSQLis võib ühes ja samas skeemis olla mitu samanimelist funktsiooni, millel on erinev arv parameetreid või erinevat tüüpi parameetrid. Seega samast funktsioonist saab olla justkui mitu realisatsiooni ning konkreetne kasutatav realisatsioon valitakse vastavalt antud sisenditele (argumentidele). See on ülelaadimise omadus.Oletame, et andmebaasis on loodud funktsioon f_lopeta_teenus, mille esimene parameeter on p_teenus_kood, mille tüüp on SMALLINT ja teine parameeter on p_selgitus, mis on tüüpi TEXT.1. Süsteem eeldab argumendi (sisendväärtuse) alusel vale parameetri andmetüüpi.Vale: SELECT f_lopeta_teenus(p_teenus_kood:=30, p_selgitus:='Osutus ebapopulaarseks');Süsteem eeldab, et parameeter p_teenus_kood on tüüpi INTEGER.Õige: SELECT f_lopeta_teenus(p_teenus_kood:=30::SMALLINT, p_selgitus:='Osutus ebapopulaarseks');::SMALLINT - tüübiteisendus tüüpi SMALLINT.2. Parameetri nimi on väljakutses valesti kirjutatud.Vale: SELECT f_lopeta_teenus(p_teenuse_kood:=30::SMALLINT, p_teenus_selgitus:='Osutus ebapopulaarseks');Õige: SELECT f_lopeta_teenus(p_teenus_kood:=30::SMALLINT, p_selgitus:='Osutus ebapopulaarseks');3. Osadele parameetritele ei anta väljakutses väärtust (argumenti) (parameetritele saab funktsiooni loomisel anda vaikimisi väärtuse ja siis ei pea nendele väljakutses väärtust andma).Vale: SELECT f_lopeta_teenus(p_teenus_kood:=30::SMALLINT);Õige: SELECT f_lopeta_teenus(p_teenus_kood:=30::SMALLINT, p_selgitus:='Osutus ebapopulaarseks');4. Funktsiooni parameetritele viitamiseks ei kasutata nime ning argumentide järjekord on väljakutses vale.Vale: SELECT f_lopeta_teenus('Osutus ebapopulaarseks', 30::SMALLINT);Õige: SELECT f_lopeta_teenus(30::SMALLINT, 'Osutus ebapopulaarseks');5. Funktsiooni otsitaks valest skeemist. Vaikimisi skeem on public. Oletame, et funktsioon on hoopis skeemis funktsioonid.Vale: SELECT f_lopeta_teenus(p_teenus_kood:=30, p_selgitus:='Osutus ebapopulaarseks');Õige: SELECT funktsioonid.f_lopeta_teenus(p_teenus_kood:=30::SMALLINT, p_selgitus:='Osutus ebapopulaarseks'); ## Küsimus: Üritan PgAdminis käivitada PostgreSQL andmebaasi vastu SQL skripti, mis sisaldab VACUUM lauseid ja saan veateate: "ERROR: VACUUM cannot run inside a transaction block". Mida teha? **Vastus:** Kui käivitate PgAdminis Query Tool akna kaudu skripti, kus on rohkem kui üks SQL lause, siis paneb PgAdmin need laused automaatselt transaktsiooni e tehingu plokki.Seega, kui käivitan andmebaasis PgAdmin kaudu laused:VACUUM FULL emp;VACUUM FULL dept;, siis tegelikult täidetakseSTART TRANSACTION;VACUUM FULL emp;VACUUM FULL dept;COMMIT;Võimalikud lahendused: käivitada kõik need laused psqlis (saab teha ka PgAdmin kaudu, valides Tools=>PSQL Tool), psql neid lauseid omast peast transaktsiooni plokki ei pane, käivitada need laused PgAdminis ükshaaval (siis neid ei panda transaktsiooni plokki), selleks võib päringu aknas lause valida(selekteerida) ja siis vajutada käivitamise nupule või klahvile F5. --- # Teema: Rakenduse tegemine ## Küsimus: Kas tehes veebirakenduse Oracle APEX vahendit kasutades on vaja luua Oracle andmebaasis kasutajaid/rolle ja jagada nendele õiguseid? **Vastus:** Kasutaja, kellena Oracle APEX suhtleb andmebaasisüsteemiga, on andmebaasis automaatselt loodud. Seda ei ole vaja muuta ning talle õiguseid jagada. Seega üliõpilased, kes teevad rakenduse Oracle APEXis, ei pea oma projekti jaoks looma looma rakendusele vastavat kasutajat ning jagama sellele õiguseid. Enda projektis kirjutate jaotistesse: "Rollid ja kasutajad" ning "Õiguste jagamine" , et töö spetsiifikast tulenevalt ei ole vaja rolle/kasutajaid luua ning õiguseid jagada. ## Küsimus: Kuhu tuleb paigutada PHPs tehtud veebirakendus? **Vastus:** Serveris apex.ttu.ee on PHP 5.5.3Serveris apex2.ttu.ee on PHP 7.4 apex.ttu.ee serveris tuleb veebirakenduse failid paigutada kataloogi /usr/local/apache2/htdocs alamkataloogi.Kui loote seal näiteks oma rakenduse jaoks kataloogi rakendus, siis rakenduse veebiaadress on: http://apex.ttu.ee/rakendus/ apex2.ttu.ee serveris tuleb veebirakenduse failid paigutada kataloogi /var/www/html alamkataloogi.Kui loote seal näiteks oma rakenduse jaoks kataloogi rakendus, siis rakenduse veebiaadress on: http://apex2.ttu.ee/rakendus/Rakenduse paigutamine aines pakutavasse serverisse ei ole kohustuslik. Kui Teil on omal server, siis võite panna sinna - peaasi, et õppejõud rakendusele lõppkasutajana ligi pääseb. Selliste serverite häda kipub küll olema, et need on sageli maas/kättesaamatud, mis raskendab töö tulemuse ülevaatust. ANDMEAAS PEAB OLEMA AINES PAKUTAVAS SERVERIS! (Oracle andmebaas apex.ttu.ee, PostgreSQL andmebaas apex2.ttu.ee) ## Küsimus: Kuidas kuvada lingitud tabeli põhjal loodud MS Accessi vormi väljas hinna juures dollari märki ($)? **Vastus:** Eeldame, et andmebaasis on vormi väljale vastav veerg arvutüüpi.Vormi väljal on selline omadus nagu vorming. Saab valida eeldefineeritud vormingu või lisada enda oma. Eeldefineeritud vormingute hulgas on Euro (väärtuse juures näidatakse euro sümbolit) ja valuuta (väärtuse juures näidatakse Windowsi seadetes määratud valuuta sümbolit).Kui tahta näidata dollari sümbolit ($), kus valuuta tähis on peale arvu, siis Kuva täisarvuna: 0" $" Kuva kaks kohta peale koma: # ##0,00" $" Kuva neli kohta peale koma: # ##0,0000" $" Vaadake näidet vastusega seotud joonistelt.Alternatiiviks on kirjutada valuuta tähis välja juures olevasse lipikusse. Seda on tehtud ka joonisel 2. **Märksõnad:** MS Access, ekraanivorm, form, format, formaat, vorming, valuuta, sümbol, lingitud tabel, linked table, USD, dollar, dollarimärk ## Küsimus: Kuidas testida, kas rakendusele vastavale kasutajale on antud õigused õigesti? **Vastus:** Muutke rakenduse konfiguratsioonis kasutajat, millena rakendus andmebaasisüsteemiga suhtleb. Selleks asendage enda (ülikasutaja õigustega) kasutajanimi/parool rakendusele vastava piiratud õigustega kasutaja (loodud CREATE USER lausega) kasutajanime ning parooliga. Näiteks pgApexis tuleb selleks muuta rohelise nupu taga ära "Database username" ja "Database password". Seejärel logige rakendusse sisse ja proovige seal teha kõiki selles realiseeritud tegevusi. Veenduge, et kõiki andmeid näeb ja kõiki andmemuudatusi saab teha. Kui sisselogimine ebaõnnestub või rakendus ei tööta nii nagu vaja (ilmuvad teated nagu "permission denied" või tühjad aruanded pgApexis), siis võib viga olla ebapiisavates õigustes. ## Küsimus: Kuidas täita pgApexis järgmiseid mittefunktsionaalseid kasutajaliidesega seotud nõudeid? Kuupäevad tuleb esitada formaadis DD.MM.YYYY Kellaajad tuleb esitada formaadis HH24:MI:SS Ajatemplid tuleb esitada formaadis DD.MM.YYYY HH24:MI:SS **Vastus:** pgApex ei võimalda hetkel muuta andmete formaati rakenduse tasemel (nagu seda võimaldab Oracle APEX). Seega tuleb teha kõik vajalikud muudatused vaadetes, mille peale luuakse andmete vaatamise leheküljed. Andmebaasi vaated ongi mõeldud selleks, et esitada kasutajatele just neid andmeid, mida nad vajavad ning just sellises formaadis nagu nad soovivad. PostgreSQLis esitatakse ajatempli (timestamp) andmed vaikimisi YYYY-MM-DD HH24:MI:SS formaadis. Mõne teise formaadi kasutamiseks vaate väärtuses tuleb vaate alampäringus kasutada to_char funktsiooni. Näide seda funktsiooni kasutavast päringust. SELECT isik_id, to_char(reg_aeg, 'DD.MM.YYYY HH24:MI:SS') AS reg_aeg, perenimi FROM Isik; Funktsiooni väljakutses on esimene argument veeru nimi, milles olevaid andmeid soovitakse formaatida ja teine argument soovitud formaat. Kuna selle funktsiooni väljund ei ole mitte tüüpi TIMESTAMP, vaid TEXT, siis ei piisa vaate muutmiseks CREATE OR REPLACE lausest (saaksite veateate: ERROR: cannot change data type of view column "reg_aeg" from timestamp to text). Selle asemel tuleb vaade kustutada ja uuesti luua. ## Küsimus: Käivitasin PostgreSQL andmebaasis lause: CREATE USER t990999_juhataja WITH PASSWORD 'juhataja'; , kuid mul ei õnnestu rakendusse kasutajanimega t990999_juhataja sisse logida. Milles on viga? **Vastus:** Rakendusele vastav andmebaasi kasutaja tuleb määrata rakenduse konfiguratsioonis (näiteks muutes pgApexis rohelise nupu taga ära "Database username" ja "Database password"). Rakendus hakkab selle kasutajana (selle kasutaja õigustes) andmebaasisüsteemiga suhtlema.Lõppkasutajale mõeldud kasutajanimi ja parool on Teil ilmselt mingis andmebaasi tabelis. Kui teete projekti töövihiku järgi (sh teete edasi kodulehelt laaditud projekti), siis on rakendusse sisselogimisel kasutajanimeks meiliaadress tabelist Isik ja parooliks sellele vastav parool tabelist Isik. ## Küsimus: Millele pöörata tähelepanu MS Accessis tehtud rakenduses, milles soovitakse VBAs välja kutsuda tekstitüüpi parameetriga PostgreSQLi andmebaasis loodud funktsiooni? **Vastus:** Kui andmebaasis on funktsiooni parameeter tekstitüüpi ning sellel on maksimaalne väljapikkus määratud (nt kauba kood – 7 märki), siis tuleb VBA koodis parameetri deklareerimisel määrata ka see väljapikkus. Näide: Juhul kui serveris oleva funktsiooni parameeter on tüüpi CHAR(7) .Parameters.Append .CreateParameter("kauba_kood", adChar, adParamInput, 7) Serveris oleva funktsiooni parameeter on tüüpi VARCHAR(7) .Parameters.Append .CreateParameter("kauba_kood", adVarChar, adParamInput, 7) ## Küsimus: Millistest üldistest põhimõtetest lähtuda andmebaasirakenduste loomisel? **Vastus:** Thomas Kyte on Oracle andmebaasisüsteemide spetsialist ja tema sellel teemal kirjutatud raamatud on väga head. Üks nendest raamatutest - Expert Oracle Database Architecture, Third Edition - on Tallinna Tehnikaülikooli üliõpilastele kättesaadav elektrooniliselt O'Reilly digitaalse platvormi kaudu. Palun lugege sellest raamatust esimese peatüki osi My Approach ja The Black Box Approach. Jah, seal kiidetakse muuhulgas Oraclet. Võtke seda kergelt, sest ka mitmed teised andmebaasisüsteemid (sh PostgreSQL) on sama võimekad. Kuid seal kirjeldatav üldine andmebaasirakenduste loomise mõtteviis on selline, mida pean mõistlikuks ja millest lähtun ka käesolevas kursuses. Põhimõte on, et hea andmebaasirakenduse loomiseks tuleks tunda ja kasutada andmebaasisüsteemide pakutavaid võimalusi. Lisan siia lõppu tsitaadi raamatust, mida ma tõlkima ei hakka. Viidatud osades tuuakse mõned ilmekad näited selle kohta, kuidas rakenduse arendajate poolne andmebaasi/andmebaasisüsteemi musta kastina vaatamine viis halbade tulemusteni. My point about the power of database features is not a criticism of tools or technologies like Hibernate, EJBs, and container-managed persistence. It is a criticism of purposely remaining ignorant of the database and how it works and how to use it. The technologies used in this case worked well—after the developers got some insight into the database itself. The bottom line is that the database is typically the cornerstone of your application. If it does not work well, nothing else really matters. If you have a black box and it does not work, what are you going to do about it? About the only thing you can do is look at it and wonder why it is not working very well. You can’t fix it, you can’t tune it. Quite simply, you do not understand how it works—and you made the decision to be in this position. The alternative is the approach that I advocate: understand your database, know how it works, know what it can do for you, and use it to its fullest potential. ## Küsimus: Saame aru, et kogu loogika peab olla ab tasemel, aga kui teeme rakendus Javas, siis meil peaks olla jdbc kiht, mis kutsub välja andmebaasis loodud protseduurid. Kas see on ok? **Vastus:** Jah, see on OK. Rõhutan, et aine fookus on andmebaasi programmeerimine. Rakenduse tegemise vahendiks soovitan midagi, mis võimaldab Teil kiiresti/lihtsalt/vähese vaevaga rakenduse valmis saada. Seetõttu sobivad näiteks hästi veebirakenduste kiirprogrammeerimise vahendid pgApex (PostgreSQL) ja Oracle Application Express (Oracle). ## Küsimus: Tegin pgApexis vaadete ekraanivorme ning avastasin, et vaatest oli väli puudu. pgApex näitas vaatele vastaval ekraanivormil päringu tulemusel saadud andmeid. Lisasin puuduva välja kustutades vastava vaate ning luues selle uuesti. Kuid nüüd ei näita pgApex enam vastavas vaates andmeid. Testimiseks tegin uue rakenduse, aga ka seal ei tekkinud otsitavad andmed. Kas ja kuidas mul oleks võimalik vaadete andmed uuesti rakendusse saada? Mida ma saaksin edaspidi teist moodi teha, et rohkem sellist probleemi ei esineks? **Vastus:** Probleem on selles, et rakendusele vastaval kasutajal pole õigust vaatest andmeid küsida (SELECT õigus). See õigus läks kaotsi, kui vaate kustutasite ja uuesti lõite (DROP lause + CREATE lause). Lahenduseks on anda rakendusele vastavale kasutajale uuesti vaadetest andmete lugemise õigus. Seega tuleb peale vaate kustutamist ja uuesti loomist käivitada ka GRANT laused vaate suhtes õiguste jagamiseks. Kui asendate vaate CREATE OR REPLACE lausega, siis on tulemuseks sama vaade ja õigused säilivad. Kuid on tõsi, et: vaatesse veeru lisamiseks, vaatest veeru eemaldamiseks, vaate veeru andmetüübi muutumisel, tuleb vaade kustutada ja uuesti luua. CREATE OR REPLACE lausest piisab, kui muudate vaadet nii, et selle veerud jäävad samaks (nt lisate või eemaldate alampäringust tingimusi). **Märksõnad:** report, aruanne, vaade, õigused, õigus, andmed --- # Teema: Õppekeskkond ## Küsimus: Kas ainel on koduleht ka Moodles? **Vastus:** Jah on.Kodulehe versioon Moodles: https://moodle.taltech.ee/course/view.php?id=32913Registreerumise võti: ITI0207_S2023Moodle leht on mõeldud selleks, et sinna registreerinud näeksid kursuse põhisündmuseid oma Moodle kalendris. Samuti panen sinna viited kõige põhilisematele materjalidele, et need, kellele Mauruse keskkond ei meeldi, peaksid seda võimalikult vähe kasutama. Mauruse lehele registreerimine on siiski vajalik. Moodle lehelt leiate otseviited Mauruse lehel olevatele materjalidele või lehe alamosadele. ## Küsimus: Kas iseseisva töö juhendi moodustavates dokumentides ja näiteprojektis on võimalik mugavalt erinevate alamosade vahel liikuda? **Vastus:** Jah on.Nendes pdf failides on järjehoidjad (bookmarks), mis võimaldavad dokumendis erinevate alamosade vahel hõlpsasti navigeerida. Kahjuks, sõltuvalt kasutatavast veebilehitsejast, ei ole see alati automaatselt esile tõstetud. Kui vaatate neid faile Firefoxi veebilehitsejas, siis on need järjehoidjad lehe vasakus servas kohe näha.Kui vaatate neid faile Chrome veebilehitsejas, siis tuleb lehe vasakust servast valida jaotis Dokumendi liigendus.Kui vaatate neid faile Edge veebilehitsejas, siis tuleb lehe vasakust ülaservast valida Sisukord.Kui vaatate neid faile Opera veebilehitsejas, siis tuleb lehe vasakust servast valida jaotis Document outline.Chrome, Edge ja Opera puhul tuleb kõige kõrgema taseme pealkirjale klõpsata, et näha selle all olevaid alampealkirju.Vastusele on lisatud illustreerivad pildid. **Märksõnad:** navigeerimine, järjehoidja, bookmark ## Küsimus: Kuidas ennast kodulehele registreerida? **Vastus:** Lehele ligipääsemiseks tuleb ennast registreerida.Palun kasutage konto juures sellist meiliaadressi, millele saabuvaid kirju Te igapäevaselt jälgite. Sellele aadressile hakkab saabuma aine korralduslik ja muu info. Seda võib vaja minna õppejõul, et Teiega ühendust võtta. Kui kasutate https://maurus.ttu.ee keskkonda esmakordselt, siis valige õppeaine lehelt menüüst Üldist=> Lehele registreerumine. Täitke vorm ja vajutage nupule "Registreeri". Kui juba olete õpikeskkonnas mingile lehele registreerunud (vahet pole, kas üks või kümme aastat tagasi), siis valige Mauruse esilehel menüüst Üldist=>Minu konto ja lisage enda aktiivsete lehtede hulka: "Andmebaasid II (ITI0207) (sügis 2023)" Ärge unustage vajutada "registreeri". Kui olete unustanud parooli, siis SIIN saab seda nullida. Kui Te ei mäleta kasutajanime/meiliaadressi, siis pöörduge õppejõu poole! Vajadusel muutke hiljem meiliaadressi, et see oleks selline, millele saabuvaid kirju Te igapäevaselt jälgite. Registreerumise järel peate ootama kuni õppejõud Teie juurdepääsu õiguse kinnitab. Kinnitamise kohta saadab süsteem automaatselt meili. ## Küsimus: Kuidas näha siin kodulehel õppeaine materjale nagu need oleks Moodles? **Vastus:** Valige Kiirvalik=> Nagu MoodlesKui meeldib, siis märkige see järjehoidjas õppeaine koduleheks. **Märksõnad:** Moodle, alternatiivne esitus ## Küsimus: Kus on kodulehel jooksvad tulemused? **Vastus:** Klõpsake Kiirvalik=>Hinneteleht (link on nähtav ainult siis, kui on avaldatavaid tulemusi). **Märksõnad:** aktiivsuspunkt, aktiivsuspunktid, lisapunkt, lisapunktid, test, testid ## Küsimus: Kus on kodulehel loengute lindistused? **Vastus:** OTSEVIIDE Echo lindistuste lehele. Seal pole paraku loengute annotatsioone (Echo keskkond laseb küll videoid kirjeldada, kuid ei näita seda infot vaataja õigustes kasutajale). Selle lingi avamiseks saate ka menüüst valida Kiirvalik=>Lindistused/LoengudSIIN on lisaks loengute annotatsioonid. **Märksõnad:** loengud, loeng, echo, lindistus, lindistused, salvestus, salvestused, video, videod ## Küsimus: Materjale on liiga palju! Kuidas tulla toime suure materjalide hulgaga? **Vastus:** Kõiki materjale ei pea sugugi lugema. Te saate valida kolme materjalide kasutamise taseme (õpiraja) vahel. Valige tase vastavalt oma huvidele ja eesmärkidele.Tase 1 Neile, kellele piisab "läbi saamisest". Loe ainult materjale: Kiirvalik => Tutvu igal juhul! Materjalid teemade kohta (paljuski korraldus), mida mujalt ei  leia. SQL-andmebaasi disainipõhimõtete ja programmeerimise kohta (seoses projekti tegemisega) ning teooria kohta leiab materjali väga paljudest allikatest. Teooria testideks saab valmistuda harjutuskeskkonnas harjutades. Tase 2 Neile, kes soovivad õpiväljundid heatasemeliselt saavutada. Loe igal nädalal materjale: Kiirvalik=>Nädala materjalid Igal nädalala jaoks kõige olulisemad materjalid. Pööra tähelepanu ka materjalide juures olevatele seotud dokumentidele. Lisaks on iga nädala kohta välja toodud soovitavad tegevused seoses ainega (nädalate peale kokku moodustab õppimise tegevuskava). Tase 3 Neile, kes soovivad süveneda ja saada põhjalikke teadmisi. Lisaks nädala materjalidele lugege ka muid materjale (alajaotis Materjalid) ning kasutajatoe küsimusi ja vastuseid (Abi => Kasutajatugi). Nädala materjalide juures on viited seotud dokumentidele ja lähedastele materjalidele. Kasutage otsingut! **Märksõnad:** Maurus, materjalid, kuidas õppida, õpirada, fail, failid ## Küsimus: Millisel viisil saab esitada soove selle kohta, kuidas muuta andmebaaside õppeaine koduleht Mauruses paremini kasutatavaks ja materjalid kergemini ülesleitavaks? **Vastus:** Soovid saab kirja panna SIIA (anonüümselt). Ma olen sealt saanud häid ideid, mille alusel olen kodulehte ja materjale parandanud. Tänan juba ette konstruktiivsete ettepanekute eest! **Märksõnad:** tagasiside, Maurus, anonüümne, kasutatavus, funktsionaalsus --- # Teema: Õppetöö ## Küsimus: Kas aine on sooritatav ka distantsilt või pigem tuleks käia koha peal? **Vastus:** Soovi korral saab suures osas õppida kohale tulemata. Soovitan siiski praktikumides kohal käia, sest elu näitab, et nii on need viljakamad ehk jõuab rohkem tehtud ja aine annab kokkuvõttes ka endale rohkem.Materjalid on kodulehel digitaalselt olemas.Loenguid lindistatakse ja neid saab ka otse vaadata - nii lindistused kui otsevaatamine on saadavad lehelt, mille leiate Kiirvalik => Lindistused/LoengudPraktikume, kus ise pikemalt räägin, proovin Teamsis lindistada. Lindistused on saadaval lehelt, mille leiate Kiirvalik => Lindistused/PraktikumidPraktikumid on Teamsis aktiivsed ja üle võrgu saab nendes kaasa töötada. Ka üle võrgu osaledes saab koguda aktiivsuspunkte.Kohal peaks olema vaid teadmiste kontrollideks - kolm vabatahtliku vahetesti semestri sees (kuigi vabatahtlikud, siis soovitan osaleda) ja lõpptest eksamisessiooni ajal. Terviseprobleemide korral saab kokkuleppel õppejõuga teha ka neid kohale tulemata. **Märksõnad:** õppetöö, kaugõpe, distantsõpe ## Küsimus: Kas eksamit saab teha enne eksamisessiooni algust? **Vastus:** Kui väga vaja, siis kokkuleppel õppejõuga saab. Eksamieeldused peavad olema eelnevalt täidetud. Kui mõtlete, et see on vajalik selleks, et eksamisessiooni ajal oma lõputööd kaitsta, siis ärge muretsege - lõputööde kaitsmine toimub eksamisessiooni teises pooles ning tehes eduka eksami eksamisessiooni esimesel nädalal jõuate ilusti kaitsmisele. **Märksõnad:** eksam, eksamisessioon ## Küsimus: Kas erinevatel nädalatel võib käia erinevates praktikumides? **Vastus:** Jah võib, eeldusel, et klassi mahute. Eriti seoses viiruste levikuga oleks hea, kui üliõpilased jaotuksid suhteliselt võrdselt erinevate praktikumide vahele, mitte ei tuleks kõik ühte tundi. ## Küsimus: Kas loengute ja praktikumide lindistusi saab vaadata ilma internetiühenduseta (offlain)? **Vastus:** Jah, saab.Echo keskkonnast saab loengute videofaile alla laadida. Kui lähete kursuse Echo lehele (valige Kiirvalik => Lindistused/Loengud) ja klõpsate lindistuse juures noolega ikoonil, siis avaneb hüpikmenüü, kust saab valida Download Original. MS Teams keskkonnad lähevad SharePoint keskkonda, kust neid on samuti võimalik alla laadida. **Märksõnad:** kaug, kaugtöö ## Küsimus: Kas magistriõppe üliõpilane, kes on bakalaureuseõppes sooritanud (saanud positiivse hinde) õppeaine "Andmebaasid II" (IDU0230), võib magistriõppes deklareerida eriõppe/põhiõppe moodulisse valikaine "Andmebaasid II" (ITI0207)? **Vastus:** Tegemist on sisuliselt sama ainega, kuid muidugi on koos tehnoloogiate arenguga ka selle sisu vahepealse aja jooksul värskenenud.Uuesti deklareerimine uue koodiga on lubatud. Ma eeldan, et soovite õppeaines oma teadmisi värskendada. See tähendab, et sooritate õppeaine täies mahus uuesti - teete projekti, vahetestid ja lõpptesti. Midagi eelmisest sooritamise korrast üle ei kanta. VÕTAga seda ainet uuesti võtta ei saa. Projekti tegemiseks pakun välja mõned "Andmebaasid I" projektid, mille hulgast saavad soovijad valida projekti, millega õppeaines "Andmebaasid II" jätkata. Alternatiivina on magistrantidel võimalik arendada projektina oma magistritöös esitatava tarkvara jaoks vajalikku andmebaasi (nagu näiteks tehti SIIN).Lisan omalt poolt, et kordamine on õppimise jaoks väga tähtis ning kindlasti leiab uuel kuulamisel midagi uut ja huvitavat, seda enam, et tehnoloogiad on pidevas muutumises. ## Küsimus: Kas seda ainet saab õppida töökohapõhist õpet kasutades? **Vastus:** Töökohapõhine õpe tähendab, et ainet õpitakse töökoha vajadusi silmas pidades ning proovitakse "lüüa kahte kärbest ühe hoobiga" - saada ise targemaks ja teha midagi kasulikku töökoha jaoks.Töökohapõhine õpe on võimalik, kuid kõik sõltub detailidest. Vaadates õpiväljundeid oleks kõige loomulikum ja võimalikum teha just projekt oma töökoha põhjal (projekt annab umbes poole aine punktidest). Tehtav projekt peab vastama õpiväljundile "Oskab disainida tehingutöötluseks mõeldud paksu jagatud SQL-andmebaasi ja programmeerida andmebaasi kasutades serveri andmebaasisüsteemi (andmebaasisüsteemide valik esitatakse semestri alguses). Lisaks oskab luua andmebaasi kasutava rakenduse ühes enda valitud vahendis." ning toetama ka teisi õpiväljundeid (turvalisuse, transaktsioonide halduse ja töökiiruse parandamise põhimõtetega tutvumine). Seega igasugune töökohapõhine töö kindlasti selle aine projektiks ei sobi. Kui näiteks juhite töö juures projekti, teete süsteemianalüüsi või arendate andmeaita, siis kõikide nende teemade jaoks on õppekavas eraldi õppeaine, milles saate töökohapõhist õpet kasutada. Töökohapõhine õpe ei tähenda, et see peaks toimuma igas õpitavas õppeaines täpselt 50% ulatuses. Võibolla mõnes aines on see 0% ja mõnes teises aines 100%. Kui tahaksite teha projekti oma töökohalt, siis peaksite selle õppejõule välja pakkuma. Edasine on juba läbirääkimiste küsimus. ## Küsimus: Kas serveriga ssh ühenduse loomiseks peab tingimata installeerima eraldi programmi nagu näiteks PuTTY? **Vastus:** Ei pea.Kui kasutate Windowsi, siis saab kasutada Windowsi koosseisus olevat OpenSSH Client programmi.Käsureale tuleb kirjutada t<matrikli number>@apex2.ttu.eeja seejärel sisestada serveri parool (vt lisatud faili).Näide: t990999@apex2.ttu.eeSelle variandi kasutamise korral on kasulik teada, kuidas Windowsi command prompt aknasse teksti kleepida.Ärge unustage, et kui olete väljaspool Eestit, siis tuleb kõigepealt luua FortiClient VPN ühendus. **Märksõnad:** vpn ## Küsimus: Kas Teil on pakkuda magistritöö (bakalaureusetöö) teemasid? **Vastus:** Magistrandid peavad juba varakult enda lõputöö teema välja valima. Seetõttu mainin ära, et olen siia kirja pannud mõned võimalikud teemad. Olen ka juhendamiseks avatud kõikidele infosüsteemide ja andmebaaside projekteerimise/programmeerimise teemadele, mida üliõpilased (oma töökohalt või mujalt saaduna) välja pakuvad. Siia olen ma kirja pannud mõtteid lõputöö teemavaliku ja võimalike teemade kohta. Siia on koondatud üldiseid viiteid lõputööde kohta.Eelnevalt viidatud allikad ja pakkumine kehtivad ka bakalaureusetööde kohta! ## Küsimus: Kas õppeaine võib deklareerida ka siis, kui eeldusaine (Andmebaasid I) on sooritamata? **Vastus:** Jah võib. Eeldusaines saadud teadmised ja oskused on sellest ainest arusaamiseks ja ainega edukalt hakkamasaamiseks vajalikud, kuid need võivad olla saadud väljastpoolt Tallinna Tehnikaülikooli või siis tuleb neid jooksvalt koguda. Paljud magistriõppe üliõpilased pole bakalaureusetasemel Tallinna Tehnikaülikoolis õppinud või kui on, siis pole "Andmebaasid I" olnud nende bakalaureuseõppe õppekavas või see on olnud valikaine, mida nad ei valinud. Seega nad ei olegi saanud eeldusainet õppida. Õppeaine "Andmebaasid II" üheks õpiväljundiks on "Oskab disainida tehingutöötluseks mõeldud paksu jagatud SQL-andmebaasi ja programmeerida andmebaasi kasutades serveri andmebaasisüsteemi (andmebaasisüsteemide valik esitatakse semestri alguses). Lisaks oskab luua andmebaasi kasutava rakenduse ühes enda valitud vahendis." Selle õpiväljundi hindamiseks tuleb teha projekt. Bakalaureuseõppe üliõpilased võtavad projekti tegemisel aluseks enda poolt õppeaines "Andmebaasid I" tehtud projekti. Üliõpilastele, kellel sellist projekti ei ole (bakalaureuseõppe üliõpilased, kellel eeldusaine on jäänud sooritamata + magistriõppe üliõpilased), valmistasin ette mõned "Andmebaasid I" projektid, mille hulgast peavad nad valima projekti, millega õppeaines "Andmebaasid II" jätkata. Leiate need kodulehe kataloogist Projekt/Projektid, mida võib jätkata. Nende projektide hulgast võivad jätkamiseks sobiva valida ka need üliõpilased, kellel on "Andmebaasid I" projekt tehtud, kuid kes ei soovi sellega mingil põhjusel jätkata. Magistriõppe üliõpilased võivad teha ka enda töökohalt pärinevat projekti. Sellise ülesandepüstituse korral on hädavajalik eelnev kokkulepe õppejõuga, sest kõik mahulised ja muud nõuded peavad ka sellise projekti puhul olema täidetud (andmeaida projekt näiteks ei sobi, sest see ei vasta õppeaine õpiväljundile). ## Küsimus: Kas üliõpilased on kohustatud käima nendele tunniplaaniga määratud aegadel praktikumis või on võimalik käia ka teiste rühmade praktikumides? **Vastus:** Ei ole kohustatud. Põhimõtteliselt on võimalik käia teisel ajal, sest sisu poolest praktikumid ei erine. Praktiline võimalus sõltub sellest, kas soovitud ajal on klassis vabu kohti. Seda on enne semestri algust raske prognoosida, sest pole teada, kui aktiivseks ühe või teise aja külastus kujuneb. Kui vabu kohti on, siis minu poolt takistust ei ole. Elu näitab, et lõpptulemusena võib olla mõnel ajal käijaid palju ja õppejõul jagub sedavõrra osalistele vähem aega mõnel teisel ajal on aga klass väga hõre ja samavõrra on õppejõul igale osaleja jaoks rohkem aega. Seega tasub alates teises õppenädalast õppejõult uurida, kas soovitud ajal on võrreldes teiste aegadega klassis liiga palju üliõpilasi ning millised on ajad, kus tunnis käijaid on vähe.Osalejate võimalikult ühtlaselt jaotumine erinevate tundide vahel aitab vähendada nakkushaiguste levimise võimalust, mis on praeguses olukorras eriti oluline! ## Küsimus: Kuidas esitada õppejõule ülevaatamiseks projekti rakenduse osa? **Vastus:** Kui Teie rakendus on veebirakendus ja üles pandud serverisse või kui Teie rakendus on tehtud MS Accessis, siis mul selle vaatamisega probleeme ei ole ja rakendust ei ole vaja tulla eraldi ette näitama. Kui Teie rakendus on vaja installeerida kasutaja arvutisse, siis see on probleem, sest minu tööarvutisse uue tarkvara lisamine on õiguste piirangute tõttu aeganõudev ja takistatud. Seega, kui rakendus vajab kasutaja arvutis mingeid lisaprogramme või tegemist on veebirakendusega, mis töötab ainult arendaja arvutis, siis pole kahjuks muud teha, kui peate rakenduse eksamisessiooni ajal ette näitama. Ettenäitamine toimub kasutades MS Teamsi ja aeg tuleb õppejõuga kokku leppida. Ükskõik millises vahendis on rakendus tehtud - tähtajaks tuleb Maurusesse üles laadida selle rakenduse lähtekood. Muidu pole tõestatud, et rakendus oli õigeks ajaks valmis. Järgnevalt kommenteerin mõningaid antud aines populaarseid rakenduse tegemise vahendeid. Oracle APEXi korral on vaja esitada eksportimise tulemus. pgApexi korral on vaja esitada apex2.ttu.ee serverist andmebaasi pgapex3 eksportimisel saadud fail (plain formaadis, SQL laused; loomiseks saate kasutada pgAdmin programmi Backup funktsiooni). MS Accessi puhul ei saa lähtekoodi saata - saadate rakenduse faili. MS Accessi puhul tuleb mulle saata *.mdb või *.accdb laiendiga fail, mitte *.mde või *.accde laiendiga fail. ## Küsimus: Kuidas moodustub hinne? Mis roll on lisapunktidel? **Vastus:** Punktid liidetakse kokku ja taandatakse Tallinna Tehnikaülikooli hindamisskaalale (0-50 punkti hinne 0; 51-60 punkti hinne 1, ..., rohkem kui 91 punkti hinne 5). Lisaks tuleb positiivse lõpphinde saamiseks ületada kaks lävendit. Projekti punktid (saate teada õppejõu poolt saadetud hindamismudeli failist). Lävendi ületamiseks on vaja vähemalt 31 punkti. Eksami punktid. Lävendi ületamiseks on vaja vähemalt 20 punkti. Eksami punktide saamiseks liidetakse: vahetestide punktid (võimalik saada kuni 18 punkti), lõpptesti punktid (võimalik saada kuni 30 punkti). Kuna vahetestide tõttu võib liitmise tulemus olla komakohtadega (nt 34.5), siis tulemus ümardatakse (nt 34.5=>35). Praktikumides kogutud aktiivsuspunktid. Vahetestide punktid aitavad ületada eksami lävendit ja suurendavad ka lõplikku punktisummat. Aktiivsuspunktid ühtegi lävendit ületada ei aita, kuid suurendavad lõplikku punktisummat. Kaotate aktiivsuspunktid (st neid ei liideta ülejäänud punktidele juurde), kui on täidetud vähemalt üks nendest tingimustest. Esimesele ülevaatusel ei ületa projekt lävendit ning saate võimaluse seda parandada. Projekti esmakordne esitamine hilineb rohkem kui kaks nädalat. ## Küsimus: Kuidas saada aktiivsuspunkte? Kas neid võib saada ka ilma tundi füüsiliselt kohale tulemata? **Vastus:** Eelistatud on, et käite praktikumis füüsiliselt kohal. Elu näitab, et nii on ka töö tulemuslikum ja õpib rohkem. Sama iseseisva töö projekti autorid võivad käia füüsiliselt erinevates praktikumides. Punkti saamiseks tuleb täita kõik järgmised tingimused. Osalete ülesande lahendamisel (oluline mainida, sest iseseisvat tööd võidakse teha rühmatööna) terve tunni jooksul. Töö peab olema võrreldes eelmise näitamisega edenenud. Olen näiteks haiguskahtlusega või haige ja ei saa praktikumi kohale tulla. Kas aktiivsuspunkte on võimalik saada?Jah on. Variant 1. Kui vähemalt üks projekti autor on füüsiliselt kohal, siis ülejäänud projekti autorid võivad osaleda koos füüsiliselt kohalolijaga kasutades MS Teamsi või mõnda muud rühmatöö keskkonda, kus veebikaamera kaudu on näha osaleja nägu. Aktiivsuspunkti saamikseks peavad nad osalema töös terve tunni. Variant 2. Kui ükski projekti autor ei tule nädala jooksul füüsiliselt praktikumi, siis saab aktiivsuspunkti kõigi järgmiste tingimuste täitmisel. Praktikumi ajal tuleb MS Teamsis ekraani jagades ette näidata viimase nädala jooksul tehtud töö. Töö peab olema võrreldes eelmise näitamisega edenenud. Punkte saavad need projekti autorid, kes on kohal MS Teamsi kõnes, st ideaalis peaksid olema kõik autorid kohal. Autori veebikaamera peab olema sisse lülitatud. **Märksõnad:** MS Teams, aktiivsuspunkt, lisapunkt, aktiivsuspunktid, lisapunktid, praktikum, praktikumid, kaug, kaugtöö ## Küsimus: Kuidas saada juurdepääs O'Reilly digitaalsele platvormile? **Vastus:** Juhend on SIIN. **Märksõnad:** oreilly ## Küsimus: Kuidas see aine reageerib COVID-19st tingitud olukorrale? **Vastus:** Tervis on kõige kallim vara. Kui õppetöö peaks uuesti minema üle täielikult distantsõppele või õppejõud haigestub, siis lülituvad kõik tegevused automaatselt ümber e-kanalitele. Ülesannetes/tähtaegades/nõudmistes ... ei muutu mitte midagi. Info töökorralduse muudatustest tuleb jooksvalt kodulehe kaudu.Kui olete haiguskahtlusega või haige, siis püsige kodus. Õppeaine korraldus arvestab sellega. Loenguid saab vaadata otseülekandena ja need ka lindistatakse. Praktikumid on MS Teamsis aktiivsed ja nendel nädalatel, kus seal ise pikemalt räägin, üritan ühte lindistada. Praktikumides saab aktiivsuspunkte koguda ning tagasisidet küsida MS Teamsi kaudu suheldes (kuid eelistatud on muidugi kohalkäimine ja kohalolijatega suhtlen esimeses järjekorras). Kui olete haiguskahtlusega või haige, siis vaheteste saab teha järgi (aga õppejõudu tuleb operatiivselt teavitada ja hilisema tegemise aeg kokku leppida). Kui olete haiguskahtlusega või haige ja eksamisessiooni lõpp on käes, siis saab teha eksamit ilma arvutiklassi kohale tulemata (jälle vajalik kokkulepe õppejõuga). Vastuvõtud toimuvad kasutades MS Teamsi. Lisaks veel: Loengu auditoorium on suur ja seal saab üksteisest eemale istuda. Praktikumides katsuge ühtlaselt jaotuda erinevate tundide vahel, et mõni tund ei oleks väga täis ja teine väga tühi. Vaheteste ja eksamit võib teha oma sülearvutis. Jäägem (testi mõttes) negatiivseks ja samas olgem (meeleolu mõttes) positiivsed! ## Küsimus: Kuidas valmistuda õppeaines toimuvateks testideks (vahetestid ja lõpptest)? **Vastus:** Kordamisküsimused ja testideks õppimise materjalid leiab kataloogist Teooria. Kordamisküsimuste dokumendi alguses on ka kirjas küsimuste valiku põhimõtted iga testi jaoks. Testide tegemine toimub veebipõhise keskkonna kaudu, kuhu Teie konto luuakse automaatselt peale seda, kui olete Mauruses õppeaine kodulehel registreerinud. NB! Süsteemis on olemas testideks harjutamise funktsionaalsus. Harjutamiseks minge lehele https://maurus.ttu.ee/testimine//valik_harjuta.php. Õppeaines toimud kolm vabatahtliku vahetesti auditoorse õppetöö perioodil ning kohustuslik lõpptest (eksam) eksamisessiooni ajal. Kõikide nende jaoks saab selles keskkonnas harjutada. Millal on mingi test harjutamiseks avatud on kirjas õppeaine kodulehe ajakavas ning perioodi algusest teavitatakse ka eraldi meili teel. Järgnevalt loetlen harjutuskeskkonna mõned olulised põhimõtted. Sisselogimiseks on Mauruse kasutajanimi ja parool. Harjutamiseks võib olla avatud rohkem kui üks test - pöörake tähelepanu, mida valite. Testi omadused (vastamiseks ettenähtud aeg; küsimuste arv; küsimuste hulk, millest testiküsimused valitakse; küsimuste valiku põhimõtted) on samasugused nagu vastaval hinnataval testil. Iga testi tegemisel genereerib süsteem uue küsimustiku. Tehtavate testide arv ei ole piiratud. Süsteemi kuritarvitamisel, et selle abil küsimusi välja pumbata (skripti kasutamine vastamiseks; küsimustiku korduv genereerimine ilma vastamiseta), blokeeritakse vastaja juurdepääs sellele testile ilma eelhoiatuseta ning jäädavalt. Iga valitava testi juures on näha ajahetk, milleni on test harjutamiseks valitud. Tulemused salvestatakse ja õppejõud näeb tulemusi. Salvestamise järel näeb vastaja õigete vastuste arvu, hinnangut vastustele ja iga küsimuse korral ka seda, kas küsimusele vastati õigesti või valesti. Iga testi puhul on määratud, kui mitmel korral päevas näeb vastaja, juhul kui ta vastas küsimusele valesti (kuid ei jätnud vastamata), ka õiget vastust. Teste võib muidugi päevas teha rohkem kui on kordi, millal näeb õigeid vastuseid. Õigeid/valesid vastuseid näeb ainult salvestamise järel, kuid mitte hiljem. Harjutamise testide tulemusi näeb hiljem ka siit. Tulemusi ei võeta õppeaine hindamisel MITTE MINGIL VIISIL arvesse (st võite julgelt harjutada ja ka eksida). ## Küsimus: Kui esitan projekti ja see on nii kehva, et pean seda parandama, siis kuidas tuleb parandus esitada? **Vastus:** Palun laadida parandatud töö Maurusesse, mitte saata seda mulle meilile. ## Küsimus: Milline on vääritu käitumine antud aine kontekstis? **Vastus:** Infotehnoloogia teaduskonnas kehtib õppuri akadeemiliste tavade rikkumise ja vääritu käitumise menetlemise kord (dokument 09). Selles dokumendis määratakse ära, milliseid õppuri poolseid tegevusi loetakse akadeemiliselt väärituks käitumiseks ning millised on tegevused ja võimalikud ametlikud tagajärjed õppuri jaoks (noomitus, eksmatrikuleerimine) kui ta millegi sellisega hakkama saab. Palun Teilt järgnevat. Ärge jagage enda tehtud projekte teiste üliõpilastega. Ärge tehke kellegi teise eest tema tööd ära. Ärge taluge projekti rühmas liikmeid, kes teistega võrdselt töösse ei panusta. Sellega teete tegelikult neile palju halba, sest nad ei õpi midagi!!! Veel enam, Te teete kahju endale, sest teadmisteta/oskusteta lõpetajad kahjustavad tööandjate silmis kõigi diplomisaajate mainet. Kui mõni projekti kaaslane ei panusta piisavalt, siis arvake ta palun oma projektist välja ja teavitage sellest (nt õppekeskkonna kaudu) õppejõudu. ## Küsimus: Milliseid linke läheb õppetöös igapäevaselt vaja, sh iseseisva töö projekti tegemisel? **Vastus:** PostgreSQL phpPgAdmin: http://apex2.ttu.ee/phppgadmin Oracle Application Express (Oracle APEX) (väljastpool ülikooli võrku looge kõigepealt FortiClient VPN ühendus): http://apex.ttu.ee:8000/apex/apex_login Oracle Application Express abil tehtud rakenduste näiteid (väljastpool ülikooli võrku looge kõigepealt FortiClient VPN ühendus): Töötajate andmebaas (rakenduse tegemiseks kulus umbes 30 minutit) (kasutajanimi: testkasutaja parool: 1234) Koristajate andmebaas (kasutajanimi: testkasutaja parool: 1234) Seisundimuudatuste realiseerimise näide APEXiga kaasa tulev näiterakendus (kasutajanimi: testkasutaja parool: 1234) 2016. aasta kevadel arendas hr Rait Raidma välja Oracle APEXile sarnase süsteemi nimega pgApex, mis põhineb PostgreSQLil. Magistritööd saab lugeda siit. 2019. aasta kevadel täiendas hr Nikolai Kopa seda tarkvara. Tema selleteemalist bakalaureusetööd saab lugeda siit. 2020. aastal andis Dmitri Bizjulin pgApexile täieliku võimekuse andmete haldamise rakenduste (CRUD rakenduste) loomiseks. Tema selleteemalist bakalaureusetööd saab lugeda siit. apex2.ttu.ee serveris üles seatud arenduskeskkond (sisselogimiseks apex kasutajanimi/parool) MIT litsentsiga kaitstud avalik lähtekood: Versioon 1 Versioon 2 Versioon 3 Tubade halduse näiterakendus (kasutajanimi: lucile.burgess@frolix.net parool: laborum) PHP rakenduse näide: Teadetetahvel - sisselogimiseks on vaja kasutada PostgreSQL kasutajanime ja parooli. Abivahendid: StarUML CASE vahendil põhinev lahendus, mis võimaldab StarUML abil koostada SQL-andmebaasi disaini mudeleid ja genereerida nendest PostgreSQLi jaoks mõeldud SQL koodi (kaasa arvatud mõningate keerukamate kitsenduste jõustamiseks vajalik kood). Idee on, et mudelis saab deklareerida kitsenduse vajaduse ning generaator oskab selle deklaratsiooni alusel koodi genereerida. apex2.ttu.ee serveris olevate PostgreSQL andmebaaside kvaliteedi kontroll - sisselogimiseks on vaja kasutada apex2.ttu.ee PostgreSQL kasutajanime ja parooli. Siin on kontrollimiseks kasutatavad päringud. Erinevad tarkvaravahendid PostgreSQL andmebaaside projekteerimiseks, programmeerimiseks ja haldamiseks. Nimekirjas on nii vaba tarkvara kui ka kommertstarkvara. Dokumentatsioon: Tigu lahkamas, ehk ekskursioon UNIXi maailma PostgreSQL dokumentatsioon PostgreSQL SQL Reference Oracle 12c Release 1 dokumentatsioon Oracle SQL Reference Ask Tom on koht kust leiab vastuseid paljudele küsimustele Oracle kohta. Ühtlasi on see keskkond näide Oracle Application Express kasutamise kohta. Oracle Application Express Oracle Application Express foorum Pistikprogrammid e pluginad, mida saab kasutada Oracle APEXI abil tehtud rakenduste funktsionaalsuse suurendamiseks. Mõned videod, mis demonstreerivad APEX 4.1 kasutamist. Lisainfo: Suur hulk soovitusi ja näpunäiteid andmebaaside programmeerijatele Visioon, kuidas üles ehitada andmete haldamiseks mõeldud süsteeme Teadmusbaas Database Lifecycle Management, kus on palju andmebaasi testimisest, evitamisest, versioonihaldusest. Tehnilisemad näited on seal MS SQL Serveri baasil, kuid üldiselt on see jutt oluline ja vajalik mistahes andmebaasisüsteemi korral. Kümme tavalist viga, mida Java arendajad teevad SQLi kirjutamisel Veel kümme tavalist viga, mida Java arendajad teevad SQLi kirjutamisel Üle kümne aasta uus väljaanne raamatus, kus andmebaasidega seotud teadus- ja arendustöö suurkujud esitavad viiteid mõnedele andmebaaside valdkonda palju ja püsivalt mõjutanud teadusartiklitele. Mis peamine, iga peatüki ees on toimetajate kommentaar, milles tutvustatakse artikleid ning kommenteeritakse andmebaasisüsteemide minevikku, olevikku ja tulevikku. Kellel on andmebaaside ja maailma selle valdkonna trendide vastu sügavam huvi, soovitan lugeda. ## Küsimus: Millist tarkvara läheb õppeaines vaja? Milline tarkvara tuleks installeerida enda isiklikku tööarvutisse? **Vastus:** Iseseisva tööga alustamisel (praktikumis alates viiendast õppenädalast) läheb vaja CASE vahendit (Enterprise Architect või Rational Rose). Selle saamise juhend on "Andmebaasid I" kodulehel. Kui Enterprise Architect on juba installeeritud, siis on vaja uuesti litsents laenutada. PostgreSQL andmebaasiga töötamiseks võib kasutada tasuta pakutavat programmi pgAdmin. Sobivad nii põlvkonnad 3 kui ka 4. Vaikimisi valik peaks olema pgAdmin 4. Juhin siiski tähelepanu, et hetkel pole põlvkonnas 4 realiseeritud graafilist päringute koostamise liidest (sarnane MS Accessi Query Designerile). See on olemas põlvkonnas 3 ja sellest võib olla abi vaadete alampäringute koostamisel, kui soovitakse mitme tabeli ühendamist nõudev vaate alampäring ilma koodi kirjutamata valmis saada. Soovi korral võib installeerida mõlemad. Kui serveris on PostgreSQL 10 või hilisem, siis pgAdmin 3 abil sisenemisel saab veateateid ja hoiatusi, kuid lõpuks võimaldab tarkvara siiski serveris olevate andmebaasidega töötada. Oracle andmebaasiga töötamiseks soovitan kasutada Oracle poolt pakutavat programmi Oracle SQL Developer (ülikooli serveriga ühenduse loomisel SID= orcl). Tarkvara on tasuta, kuid selle allalaadimiseks tuleb ennast registreerida. Serveriga SSH ühenduse loomiseks võib kasutada näiteks programme PuTTY, Bitvise SSH Client või Windowsi koosseisus olev OpenSSH client. Selles lõigus nimetatud programmidest piisab ühest! Serverisse failide ülekandmiseks ja sealt failide allalaadimiseks võib kasutada programmi WinSCP. Tegelikult sisaldab ka Bitvise sellist funktsionaalsust ja siis poleks WinSCPd vajagi. Lähtekoodiga (sh SQL lausetega) töötamiseks sobib hästi tekstiredaktor SciTe või Notepad++. Valikuline PostgreSQL andmebaasisüsteemi kasutava kahekihilise klient-server süsteemi loomiseks läheb vaja PostgreSQL ODBC draivereid. Valige palun kõige viimane versioon. Kui olete juba installeerinud mõne varasema versiooni, siis see tuleb kõigepealt arvutist maha võtta ja siis installeerida draiveri uuem versioon. Milline draiver täpsemalt valida ja kuidas andmeühendust seadistada lugege palun teatele lisatud failist. Kui Teile meeldib käsureapõhine kasutajaliides ja peate (õigusega) Oracle SQL*Plus'i liiga vanamoodsaks, siis võite enda arvutisse installeerida Oracle SQLcl. See on Oracle SQL*Plus edasiarendus. Kui kasutate enda arvutisse installeeritud Oracle SQLcl versiooni või kasutate Windowsi OpenSSH client programmi, siis on kasulik teada, kuidas Windowsi command prompt aknasse teksti kleepida. Kui PostgreSQLiga suhtlemiseks pakutud vahenditest väheks jääb, siis siit leiab veel alternatiive.   **Märksõnad:** software, soft, töövahendid ## Küsimus: Mul ei õnnestu vaadata loengute lindistusi, sest saan videote vaatamisel veateate. ERROR:Unable to process language file located at: language/ru.xml The file is either missing or corrupt. **Vastus:** Ilmselt on probleem selles, et veebilehitseja on venekeelne. Lahendus oleks kasutada ingliskeelset veebilehitseja. Ehk siis peaksite ära muutma keele sätted. GoogleChromes saaks korda kui võtta Настройка и управление Google Chrome Настройки ->Показать дополнительные настройки -> Языки ->Настройка языков и способов ввода ja võtate kasutusse inglise keele (англиский (США)). ## Küsimus: Saan MS Teamsi avamisel teate "Me ei saanud ühendust luua. Logi sisse ja proovime uuesti". Uuesti proovimine ei aita. Mida teha? **Vastus:** SIIN on tegevusjuhend, mida tasub proovida sellisest veast vabanemiseks. Credential manager = Mandaadihaldur. Sulgege Teams. Avage tegumihaldur (Ctrl+Alt+Del) ja kustutage kõik MS Teamsi tegumid.%appdata%\Microsoft\teams saab kirjutada Windowsi otsingusse ja kataloog avatakse automaatselt.Peale kataloogi sisu kustutamist ja enne Teamsi uuesti sisselogimist võiks teha arvuti taaskäivituse. **Märksõnad:** MS Teams, kaug, kaugtöö ## Küsimus: Teen järjest aineid ette ära, et saaksin kogu rõhu lõputööle panna. Sooviksin homme projekti kaitsta. Kas nii saab? **Vastus:** Kaitsmist kui sellist siin aines ei ole. Peale töö lõplikku valmimist esitab üliõpilane selle ülevaatamiseks ning saab hindamismudeli alusel punktid. Hindamismudeli alusel hindamise juures üliõpilane ei osale. Peale hindamist saab ta täidetud hindamismudeli faili. Peale esitamist saab tööd parandada või täiendada vaid siis, kui töö eest saadavad punktid ei ületa lävendit (31 punkti). Enne esitamist saab tööd piiramatu arv kordi lihtsalt näidata ja selle kohta küsida. Seega homme võiksite oma tööd veelkord näidata, sh dokumenti. See ei ole ametlik hindamine. Peale seda, kui tunnete, et nüüd on töö tõesti valmis, saate selle õppekeskkonna kaudu hindamiseks ära esitada. ## Küsimus: Teen projekti PostgreSQLis/Oracles. Kas mul on siis vaja praktikumides tutvuda teise andmebaasisüsteemiga (Oracle/PostgreSQL) ja selle kasutamiseks vajalik tarkvara enda sülearvutisse installeerida? **Vastus:** Ma kujutan ette, et üliõpilased tahaksid ennast tulevaseks tööeluks võimalikult mitmekülgselt ette valmistada ja seega ülikooli liivakastis erinevaid asju katsetada. Formaalselt rääkides, siis kõik testid küsivad küsimusi nii PostgreSQL kui Oracle kohta. Eeldan, et üliõpilased on tuttavad kõige sellega, mis kodulehe materjalides on kirjas. Oracle SQL Developer/pgAdmin tasub endale Oracle/PostgreSQL katsetamise huvides installeerida, isegi kui Te projekti Oracles/PostgreSQLis ei tee. Sellel põhjusel on ka samm-sammulise juhendi moodustavates praktikumi ülesannetes üheskoos info nii PostgreSQL kui Oracle kohta.