Balansiranje pisanja i čitanja u bazi podataka

Balansiranje pisanja i čitanja u bazi podataka
U prethodnom članak Opisao sam koncept i implementaciju baze podataka izgrađene na bazi funkcija, a ne na tabelama i poljima kao u relacionim bazama podataka. Dalo je mnogo primjera koji pokazuju prednosti ovog pristupa u odnosu na klasični. Mnogi su ih smatrali nedovoljno uvjerljivima.

U ovom članku ću pokazati kako vam ovaj koncept omogućava brzo i praktično balansiranje upisivanja i čitanja u bazu podataka bez ikakvih promjena u operativnoj logici. Slična funkcionalnost je pokušana da se implementira u moderne komercijalne DBMS (posebno, Oracle i Microsoft SQL Server). Na kraju članka ću pokazati da ono što su uradili, najblaže rečeno, nije išlo baš najbolje.

Opis

Kao i ranije, radi boljeg razumijevanja započeću opis primjerima. Recimo da treba da implementiramo logiku koja će vratiti listu odeljenja sa brojem zaposlenih u njima i njihovom ukupnom platom.

U funkcionalnoj bazi podataka to bi izgledalo ovako:

CLASS Department ‘Отдел’;
name ‘Наименование’ = DATA STRING[100] (Department);

CLASS Employee ‘Сотрудник’;
department ‘Отдел’ = DATA Department (Employee);
salary ‘Зарплата’ =  DATA NUMERIC[10,2] (Employee);

countEmployees ‘Кол-во сотрудников’ (Department d) = 
    GROUP SUM 1 IF department(Employee e) = d;
salarySum ‘Суммарная зарплата’ (Department d) = 
    GROUP SUM salary(Employee e) IF department(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);

Složenost izvršavanja ovog upita u bilo kojem DBMS-u će biti jednaka O (broj zaposlenih)jer ova kalkulacija zahteva skeniranje cele tabele zaposlenih i njihovo grupisanje po odeljenjima. Postojaće i neki mali (vjerujemo da ima mnogo više zaposlenih nego odjela) dodatak ovisno o odabranom planu O (dnevni broj zaposlenih) ili O (broj odjela) za grupisanje i tako dalje.

Jasno je da troškovi izvršenja mogu biti različiti u različitim DBMS-ovima, ali se složenost neće promijeniti ni na koji način.

U predloženoj implementaciji, funkcionalni DBMS će generirati jedan potupit koji će izračunati potrebne vrijednosti za odjel, a zatim napraviti JOIN sa tablicom odjela kako bi dobio ime. Međutim, za svaku funkciju, prilikom deklarisanja, moguće je postaviti poseban marker MATERIALIZED. Sistem će automatski kreirati odgovarajuće polje za svaku takvu funkciju. Prilikom promjene vrijednosti funkcije, vrijednost polja će se također promijeniti u istoj transakciji. Prilikom pristupa ovoj funkciji, pristupit će se unaprijed izračunatom polju.

Posebno, ako postavite MATERIALIZED za funkcije countEmployees и salarySum, tada će se u tabelu sa listom odjeljenja dodati dva polja u kojima će se čuvati broj zaposlenih i njihova ukupna plata. Kad god dođe do promjene zaposlenih, njihovih plata ili pripadnosti odjeljenjima, sistem će automatski promijeniti vrijednosti ovih polja. Gornji upit će direktno pristupiti ovim poljima i u njima će se izvršiti O (broj odjela).

Koja su ograničenja? Samo jedno: takva funkcija mora imati konačan broj ulaznih vrijednosti za koje je definirana njena vrijednost. U suprotnom, biće nemoguće napraviti tabelu koja čuva sve svoje vrednosti, jer ne može postojati tabela sa beskonačnim brojem redova.

Primjer:

employeesCount ‘Количество сотрудников с зарплатой > N’ (Department d, NUMERIC[10,2] N) = 
    GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;

Ova funkcija je definirana za beskonačan broj vrijednosti N (na primjer, bilo koja negativna vrijednost je prikladna). Stoga, ne možete staviti MATERIALIZED na njega. Dakle, ovo je logično ograničenje, a ne tehničko (to jest, ne zato što ga nismo mogli implementirati). Inače, nema ograničenja. Možete koristiti grupisanje, sortiranje, I i ILI, PARTICIJA, rekurzija itd.

Na primjer, u problemu 2.2 prethodnog članka, možete staviti MATERIALIZED na obje funkcije:

bought 'Купил' (Customer c, Product p, INTEGER y) = 
    GROUP SUM sum(Detail d) IF 
        customer(order(d)) = c AND 
        product(d) = p AND 
        extractYear(date(order(d))) = y MATERIALIZED;
rating 'Рейтинг' (Customer c, Product p, INTEGER y) = 
    PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y MATERIALIZED;
SELECT contactName(Customer c), name(Product p) WHERE rating(c, p, 1997) < 3;

Sam sistem će kreirati jednu tabelu sa tipskim ključevima kupac, Proizvod и INTEGER, će mu dodati dva polja i ažurirati vrijednosti polja u njima sa svim promjenama. Kada se izvrše daljnji pozivi ovih funkcija, one se neće izračunavati, već će se vrijednosti čitati iz odgovarajućih polja.

Koristeći ovaj mehanizam, možete se, na primjer, riješiti rekurzija (CTE) u upitima. Konkretno, razmotrite grupe koje formiraju stablo koristeći odnos dijete/roditelj (svaka grupa ima vezu sa svojim roditeljem):

parent = DATA Group (Group);

U funkcionalnoj bazi podataka, logika rekurzije se može specificirati na sljedeći način:

level (Group child, Group parent) = RECURSION 1l IF child IS Group AND parent == child
                                                             STEP 2l IF parent == parent($parent);
isParent (Group child, Group parent) = TRUE IF level(child, parent) MATERIALIZED;

Pošto za funkciju isParent je označeno MATERIJALIZOVANO, tada će se za njega kreirati tabela sa dva ključa (grupe) u kojoj je polje isParent bit će istinit samo ako je prvi ključ dijete drugog. Broj unosa u ovoj tabeli biće jednak broju grupa pomnoženim sa prosečnom dubinom stabla. Ako trebate, na primjer, izbrojati broj potomaka određene grupe, možete koristiti ovu funkciju:

childrenCount (Group g) = GROUP SUM 1 IF isParent(Group child, g);

U SQL upitu neće biti CTE. Umjesto toga postojat će jednostavna GROUP BY.

Koristeći ovaj mehanizam, također možete lako denormalizirati bazu podataka ako je potrebno:

CLASS Order 'Заказ';
date 'Дата' = DATA DATE (Order);

CLASS OrderDetail 'Строка заказа';
order 'Заказ' = DATA Order (OrderDetail);
date 'Дата' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;

Prilikom pozivanja funkcije datum za red narudžbe, polje za koje postoji indeks će se pročitati iz tabele sa redovima naloga. Kada se promijeni datum narudžbe, sam sistem će automatski ponovo izračunati denormalizirani datum u retku.

Prednosti

Čemu služi cijeli ovaj mehanizam? U klasičnim DBMS-ovima, bez ponovnog pisanja upita, programer ili DBA mogu samo promijeniti indekse, odrediti statistiku i reći planeru upita kako da ih izvrši (a HINT-ovi su dostupni samo u komercijalnim DBMS-ovima). Koliko god se trudili, neće moći ispuniti prvi upit u članku u O (broj odjela) bez mijenjanja upita ili dodavanja okidača. U predloženoj shemi, u fazi razvoja ne morate razmišljati o strukturi pohrane podataka i koje agregacije koristiti. Sve se to može lako promijeniti u hodu, direktno u radu.

U praksi to izgleda ovako. Neki ljudi razvijaju logiku direktno na osnovu zadatka. Ne razumiju algoritme i njihovu složenost, ni planove izvršenja, ni vrste spojeva, niti bilo koju drugu tehničku komponentu. Ovi ljudi su više poslovni analitičari nego programeri. Zatim, sve ovo ide u testiranje ili rad. Omogućava evidentiranje dugotrajnih upita. Kada se otkrije dugačak upit, onda drugi ljudi (više tehnički - u suštini DBA) odlučuju da omoguće MATERIALIZED na nekoj srednjoj funkciji. Ovo malo usporava snimanje (pošto zahteva ažuriranje dodatnog polja u transakciji). Međutim, nije samo ovaj upit značajno ubrzan, već i svi ostali koji koriste ovu funkciju. Istovremeno, relativno je lako odlučiti koja će se funkcija materijalizirati. Dva glavna parametra: broj mogućih ulaznih vrijednosti (ovo je koliko će zapisa biti u odgovarajućoj tabeli) i koliko se često koristi u drugim funkcijama.

Analogi

Moderni komercijalni DBMS-ovi imaju slične mehanizme: MATERIJALIZOVANI PREGLED sa FAST REFRESH (Oracle) i INDEKSIRANI PREGLED (Microsoft SQL Server). U PostgreSQL-u, MATERIJALIZOVANI POGLED se ne može ažurirati u transakciji, već samo na zahtjev (pa čak i uz vrlo stroga ograničenja), tako da to ne uzimamo u obzir. Ali imaju nekoliko problema koji značajno ograničavaju njihovu upotrebu.

Prvo, možete omogućiti materijalizaciju samo ako ste već kreirali običan PREGLED. U suprotnom, morat ćete prepisati preostale zahtjeve za pristup novokreiranom pogledu da biste koristili ovu materijalizaciju. Ili ostavite sve kako jeste, ali će biti u najmanju ruku neučinkovito ako postoje određeni već unaprijed izračunati podaci, ali mnogi upiti ih ne koriste uvijek, već ih preračunavaju.

Drugo, oni imaju ogroman broj ograničenja:

proročanstvo

5.3.8.4 Opšta ograničenja za brzo osvježavanje

Upit za definiranje materijaliziranog pogleda je ograničen na sljedeći način:

  • Materijalizirani pogled ne smije sadržavati reference na izraze koji se ne ponavljaju kao SYSDATE i ROWNUM.
  • Materijalizirani pogled ne smije sadržavati reference na RAW or LONG RAW tipovi podataka.
  • Ne može sadržavati a SELECT list potupit.
  • Ne može sadržavati analitičke funkcije (npr. RANK) u SELECT klauzula.
  • Ne može referencirati tabelu na kojoj je an XMLIndex indeks je definiran.
  • Ne može sadržavati a MODEL klauzula.
  • Ne može sadržavati a HAVING klauzula sa podupitom.
  • Ne može sadržavati ugniježđene upite koji imaju ANY, ALL, ili NOT EXISTS.
  • Ne može sadržavati a [START WITH …] CONNECT BY klauzula.
  • Ne može sadržavati više tabela detalja na različitim lokacijama.
  • ON COMMIT materijalizirani pogledi ne mogu imati udaljene tabele detalja.
  • Ugniježđeni materijalizirani pogledi moraju imati spoj ili agregat.
  • Materijalizovani spojeni pogledi i materijalizovani agregatni pogledi sa a GROUP BY klauzula ne može birati iz indeksno organizirane tablice.

5.3.8.5 Ograničenja za brzo osvježavanje na materijaliziranim pogledima samo sa spajanjem

Definiranje upita za materijalizirane poglede samo sa spojevima i bez agregata ima sljedeća ograničenja za brzo osvježavanje:

  • Sva ograničenja od «Opća ograničenja za brzo osvježavanje".
  • Ne mogu imati GROUP BY klauzule ili agregate.
  • Redovi svih tabela u FROM lista se mora pojaviti u SELECT listu upita.
  • Materijalizirani zapisnici pogleda moraju postojati sa rowidovima za sve osnovne tablice u FROM listu upita.
  • Ne možete kreirati materijalizirani prikaz koji se može brzo osvježiti iz više tabela s jednostavnim spojevima koji uključuju stupac tipa objekta u SELECT izjava.

Također, metoda osvježavanja koju odaberete neće biti optimalno efikasna ako:

  • Upit za definiranje koristi vanjski spoj koji se ponaša kao unutrašnji spoj. Ako definirajući upit sadrži takvo spajanje, razmislite o ponovnom pisanju upita za definiranje tako da sadrži unutrašnje spajanje.
  • The SELECT lista materijalizovanog pogleda sadrži izraze na kolonama iz više tabela.

5.3.8.6 Ograničenja brzog osvježavanja materijaliziranih pogleda sa agregatima

Definiranje upita za materijalizirane poglede sa agregatima ili spojevima ima sljedeća ograničenja za brzo osvježavanje:

Brzo osvježavanje je podržano za oba ON COMMIT i ON DEMAND materijalizovani pogledi, međutim važe sljedeća ograničenja:

  • Sve tabele u materijalizovanom pogledu moraju imati materijalizovane dnevnike pogleda, a materijalizovani zapisnici pogleda moraju:
    • Sadrži sve kolone iz tabele na koje se upućuje u materijalizovanom pogledu.
    • Navedite sa ROWID i INCLUDING NEW VALUES.
    • Navedite SEQUENCE klauzulu ako se očekuje da tabela ima mješavinu umetanja/direktnog učitavanja, brisanja i ažuriranja.

  • samo SUM, COUNT, AVG, STDDEV, VARIANCE, MIN i MAX su podržani za brzo osvježavanje.
  • COUNT(*) mora biti specificirano.
  • Agregatne funkcije se moraju pojaviti samo kao najudaljeniji dio izraza. Odnosno, agregati kao npr AVG(AVG(x)) or AVG(x)+ AVG(x) nisu dozvoljeni.
  • Za svaki agregat kao npr AVG(expr), odgovarajući COUNT(expr) mora biti prisutan. Oracle to preporučuje SUM(expr) biti specificiran.
  • If VARIANCE(expr) or STDDEV(expr) je navedeno, COUNT(expr) i SUM(expr) mora biti specificirano. Oracle to preporučuje SUM(expr *expr) biti specificiran.
  • The SELECT stupac u upitu za definiranje ne može biti složen izraz sa stupcima iz više osnovnih tablica. Moguće rješenje za ovo je korištenje ugniježđenog materijaliziranog pogleda.
  • The SELECT lista mora sadržavati sve GROUP BY kolone.
  • Materijalizovani pogled nije zasnovan na jednoj ili više udaljenih tabela.
  • Ako koristite CHAR tip podataka u kolonama filtera dnevnika materijaliziranog prikaza, skupovi znakova glavne stranice i materijaliziranog pogleda moraju biti isti.
  • Ako materijalizirani pogled ima jedno od sljedećeg, tada je brzo osvježavanje podržano samo na konvencionalnim DML umetcima i direktnim učitavanjima.
    • Materijalizovani pogledi sa MIN or MAX agregati
    • Materijalizovani pogledi koji imaju SUM(expr) ali ne COUNT(expr)
    • Materijalizovani pogledi bez COUNT(*)

    Takav materijalizirani pogled naziva se materijalizirani pogled samo za umetanje.

  • Materijalizovan pogled sa MAX or MIN se brzo osvježava nakon brisanja ili miješanih DML naredbi ako nema a WHERE klauzula.
    Maksimalno/min brzo osvježavanje nakon brisanja ili miješanog DML-a nema isto ponašanje kao slučaj samo za umetanje. Briše i ponovo izračunava maksimalne/min vrijednosti za pogođene grupe. Morate biti svjesni njegovog utjecaja na performanse.
  • Materijalizirani pogledi s imenovanim pogledima ili podupitima u FROM klauzula se može brzo osvježiti pod uvjetom da se pogledi mogu u potpunosti spojiti. Za informacije o tome koji će se pogledi spojiti, pogledajte Referenca za jezik Oracle baze podataka SQL.
  • Ako nema vanjskih spojeva, možete imati proizvoljne odabire i spojeve u WHERE klauzula.
  • Materijalizirani agregatni pogledi s vanjskim spojevima se brzo mogu osvježiti nakon konvencionalnog DML-a i direktnog učitavanja, pod uvjetom da je samo vanjska tablica izmijenjena. Također, moraju postojati jedinstvena ograničenja na stupcima spajanja unutrašnje tabele spajanja. Ako postoje vanjski spojevi, svi spojevi moraju biti povezani pomoću ANDs i mora koristiti jednakost (=) operater.
  • Za materijalizovane poglede sa CUBE, ROLLUP, grupisanje skupova ili njihovo spajanje, primjenjuju se sljedeća ograničenja:
    • The SELECT lista treba sadržavati razlikovač grupisanja koji može biti a GROUPING_ID funkcija na svim GROUP BY izrazi ili GROUPING funkcije jedna za svaku GROUP BY izraz. Na primjer, ako je GROUP BY klauzula materijalizovanog pogleda je "GROUP BY CUBE(a, b)“, zatim SELECT lista treba sadržavati ili "GROUPING_ID(a, b)» ili «GROUPING(a) AND GROUPING(b)» da bi se materijalizirani prikaz brzo osvježio.
    • GROUP BY ne bi trebalo rezultirati duplim grupama. Na primjer, "GROUP BY a, ROLLUP(a, b)" se ne može brzo osvježiti jer rezultira duplim grupiranjima "(a), (a, b), AND (a)".

5.3.8.7 Ograničenja za brzo osvježavanje na materijaliziranim pogledima sa UNION ALL

Materijalizovani pogledi sa UNION ALL podesiti podršku operatera REFRESH FAST opciju ako su ispunjeni sljedeći uslovi:

  • Upit za definiranje mora imati UNION ALL operater na najvišem nivou.

    The UNION ALL operator ne može biti ugrađen unutar potupita, s jednim izuzetkom: The UNION ALL može biti u potupitu u FROM klauzulu pod uvjetom da je upit za definiranje u obliku SELECT * FROM (pregled ili podupit sa UNION ALL) kao u sljedećem primjeru:

    CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM kupaca c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM kupaca c WHERE c.cust_la 'Jones'); NAPRAVITE MATERIJALIZOVANI PREGLED unionall_inside_view_mv BRZO OSVEŽITE NA ZAHTEV KAO SELECT * FROM view_with_unionall;
    

    Imajte na umu da pogled view_with_unionall zadovoljava zahtjeve za brzo osvježavanje.

  • Svaki blok upita u UNION ALL upit mora zadovoljiti zahtjeve materijaliziranog pogleda koji se brzo može osvježiti sa agregatima ili materijaliziranog pogleda koji se brzo može osvježiti sa spojevima.

    Odgovarajući zapisnici materijaliziranog pogleda moraju se kreirati na tablicama kako je potrebno za odgovarajući tip materijaliziranog pogleda koji se brzo može osvježiti.
    Imajte na umu da Oracle Database takođe dozvoljava poseban slučaj materijalizovanog pogleda jedne tabele sa spojevima samo pod uslovom ROWID kolona je uključena u SELECT listu iu materijalizovanom dnevniku pogleda. Ovo je prikazano u upitu za definiranje pogleda view_with_unionall.

  • The SELECT lista svakog upita mora sadržavati a UNION ALL marker, i UNION ALL kolona mora imati različitu konstantnu numeričku ili string vrijednost u svakoj UNION ALL grana. Nadalje, kolona markera mora se pojaviti na istom rednom mjestu u SELECT lista svakog bloka upita. vidi "UNION ALL Marker i prepisivanje upita» za više informacija o UNION ALL markeri.
  • Neke funkcije kao što su vanjski spojevi, upiti za materijalizirane poglede samo za umetanje i udaljene tablice nisu podržane za materijalizirane poglede sa UNION ALL. Imajte na umu, međutim, da se materijalizirani pogledi koji se koriste u replikaciji, a koji ne sadrže spojeve ili agregate, mogu brzo osvježiti kada UNION ALL ili se koriste udaljeni stolovi.
  • Parametar inicijalizacije kompatibilnosti mora biti postavljen na 9.2.0 ili noviji kako bi se kreirao materijalizirani prikaz koji se može brzo osvježiti sa UNION ALL.

Ne želim da uvrijedim fanove Oraclea, ali sudeći po njihovoj listi ograničenja, čini se da je ovaj mehanizam napisan ne u opštem slučaju, po nekakvom modelu, već od strane hiljada Indijaca, gdje su svi dobili priliku napisati svoju granu, i svako od njih je radio šta je mogao. Korištenje ovog mehanizma za pravu logiku je kao hodanje kroz minsko polje. Možete dobiti minu u bilo kojem trenutku pritiskom na jedno od neočiglednih ograničenja. Kako to funkcionira je također zasebno pitanje, ali to je izvan okvira ovog članka.

Microsoft SQLServer

Dodatni zahtjevi

Pored SET opcija i zahtjeva determinističke funkcije, moraju biti ispunjeni sljedeći zahtjevi:

  • Korisnik koji izvršava CREATE INDEX mora biti vlasnik pogleda.
  • Kada kreirate indeks, IGNORE_DUP_KEY opcija mora biti postavljena na OFF (podrazumevana postavka).
  • Tabele se moraju referencirati dvodijelnim imenima, shema.tablename u definiciji pogleda.
  • Korisnički definirane funkcije na koje se upućuje u prikazu moraju se kreirati korištenjem WITH SCHEMABINDING opcija.
  • Sve korisnički definirane funkcije koje se referenciraju u pogledu moraju biti referencirane dvodijelnim imenima, ..
  • Svojstvo pristupa podacima korisnički definirane funkcije mora biti NO SQL, a svojstvo vanjskog pristupa mora biti NO.
  • Funkcije Common Language Runtime (CLR) mogu se pojaviti na listi odabira pogleda, ali ne mogu biti dio definicije klasteriziranog indeksnog ključa. CLR funkcije se ne mogu pojaviti u klauzuli WHERE pogleda ili ON klauzule operacije JOIN u pogledu.
  • CLR funkcije i metode CLR korisnički definiranih tipova korištenih u definiciji pogleda moraju imati svojstva postavljena kao što je prikazano u sljedećoj tablici.

    imovina
    Bilješka

    DETERMINISTIČKA = TRUE
    Mora biti eksplicitno deklarisan kao atribut metode Microsoft .NET Framework.

    PRECIZNO = TAČNO
    Mora biti eksplicitno deklariran kao atribut metode .NET Framework.

    PRISTUP PODACIMA = NEMA SQL-a
    Određuje se postavljanjem atributa DataAccess na DataAccessKind.None i SystemDataAccess atributa na SystemDataAccessKind.None.

    VANJSKI PRISTUP = NE
    Ovo svojstvo je zadano na NE za CLR rutine.

  • Pogled se mora kreirati korištenjem WITH SCHEMABINDING opcija.
  • Pogled mora referencirati samo osnovne tablice koje se nalaze u istoj bazi podataka kao i pogled. Pogled ne može referencirati druge poglede.
  • Izraz SELECT u definiciji pogleda ne smije sadržavati sljedeće Transact-SQL elemente:

    COUNT
    ROWSET funkcije (OPENDATASOURCE, OPENQUERY, OPENROWSET, I OPENXML)
    OUTER pridružuje (LEFT, RIGHT, ili FULL)

    Izvedena tabela (definisana navođenjem a SELECT izjava u FROM klauzula)
    Self-joins
    Određivanje stupaca pomoću SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARP, ili AVG
    Zajednički tabelarni izraz (CTE)

    float1, tekst, ntext, slika, XML, ili filestream kolone
    Podupit
    OVER klauzulu, koja uključuje rangiranje ili agregatne funkcije prozora

    Predikati punog teksta (CONTAINS, FREETEXT)
    SUM funkcija koja referencira izraz koji može biti nullable
    ORDER BY

    CLR korisnički definirana agregatna funkcija
    TOP
    CUBE, ROLLUP, ili GROUPING SETS operatera

    MIN, MAX
    UNION, EXCEPT, ili INTERSECT operatera
    TABLESAMPLE

    Tabelarne varijable
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Retki skupovi kolona
    Inline (TVF) ili funkcije s tabličnim vrijednostima s više iskaza (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Indeksirani prikaz može sadržavati float stupovi; međutim, takvi stupci ne mogu biti uključeni u klasterirani indeksni ključ.

  • If GROUP BY je prisutna, definicija VIEW mora sadržavati COUNT_BIG(*) i ne smije sadržavati HAVING. ovi GROUP BY ograničenja su primjenjiva samo na definiciju indeksiranog pogleda. Upit može koristiti indeksirani pogled u svom planu izvršenja čak i ako ne zadovoljava ove GROUP BY ograničenja.
  • Ako definicija pogleda sadrži a GROUP BY klauzulu, ključ jedinstvenog grupisanog indeksa može referencirati samo stupce specificirane u GROUP BY klauzula.

Ovdje je jasno da Indijanci nisu bili uključeni, jer su odlučili da to urade po shemi „malo ćemo, ali dobro“. Odnosno, imaju više mina na terenu, ali je njihova lokacija transparentnija. Ono što najviše razočarava je ovo ograničenje:

Pogled mora referencirati samo osnovne tablice koje se nalaze u istoj bazi podataka kao i pogled. Pogled ne može referencirati druge poglede.

U našoj terminologiji, to znači da funkcija ne može pristupiti drugoj materijaliziranoj funkciji. Time se u korenu ukida svaka ideologija.
Također, ovo ograničenje (i dalje u tekstu) uvelike smanjuje slučajeve upotrebe:

Izraz SELECT u definiciji pogleda ne smije sadržavati sljedeće Transact-SQL elemente:

COUNT
ROWSET funkcije (OPENDATASOURCE, OPENQUERY, OPENROWSET, I OPENXML)
OUTER pridružuje (LEFT, RIGHT, ili FULL)

Izvedena tabela (definisana navođenjem a SELECT izjava u FROM klauzula)
Self-joins
Određivanje stupaca pomoću SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARP, ili AVG
Zajednički tabelarni izraz (CTE)

float1, tekst, ntext, slika, XML, ili filestream kolone
Podupit
OVER klauzulu, koja uključuje rangiranje ili agregatne funkcije prozora

Predikati punog teksta (CONTAINS, FREETEXT)
SUM funkcija koja referencira izraz koji može biti nullable
ORDER BY

CLR korisnički definirana agregatna funkcija
TOP
CUBE, ROLLUP, ili GROUPING SETS operatera

MIN, MAX
UNION, EXCEPT, ili INTERSECT operatera
TABLESAMPLE

Tabelarne varijable
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Retki skupovi kolona
Inline (TVF) ili funkcije s tabličnim vrijednostima s više iskaza (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY i drugi su zabranjeni. Možda je bilo lakše odrediti šta se može koristiti, a ne šta se ne može koristiti. Lista bi vjerovatno bila mnogo manja.

Da rezimiramo: ogroman skup ograničenja u svakom (zapazimo komercijalno) DBMS naspram nijednog (s izuzetkom jednog logičkog, a ne tehničkog) u LGPL tehnologiji. Međutim, treba napomenuti da je implementacija ovog mehanizma u relacionoj logici nešto teža nego u opisanoj funkcionalnoj logici.

Реализация

Kako radi? PostgreSQL se koristi kao „virtuelna mašina“. Unutra je složen algoritam koji pravi upite. Evo izvor. I ne postoji samo veliki skup heuristike sa gomilom ako. Dakle, ako imate nekoliko mjeseci za učenje, možete pokušati razumjeti arhitekturu.

Da li djeluje efikasno? Prilično efektno. Nažalost, ovo je teško dokazati. Mogu samo reći da ako uzmete u obzir hiljade upita koji postoje u velikim aplikacijama, onda su oni u prosjeku efikasniji od onih kod dobrog programera. Odličan SQL programer može efikasnije napisati bilo koji upit, ali sa hiljadu upita jednostavno neće imati ni motivacije ni vremena da to uradi. Jedino što sada mogu navesti kao dokaz efikasnosti je da nekoliko projekata radi na platformi izgrađenoj na ovom DBMS-u ERP sistemi, koji imaju hiljade različitih MATERIJALIZOVANIH funkcija, sa hiljadama korisnika i terabajtnim bazama podataka sa stotinama miliona zapisa koji rade na redovnom serveru sa dva procesora. Međutim, svako može provjeriti/pobiti efektivnost preuzimanjem platforma i PostgreSQL, upaljen evidentiranje SQL upita i pokušaj promjene logike i podataka tamo.

U sljedećim člancima ću također govoriti o tome kako možete postaviti ograničenja na funkcije, raditi sa sesijama promjena i još mnogo toga.

izvor: www.habr.com

Dodajte komentar