
I den forrige beskrev jeg konceptet og implementeringen af en database, der er bygget på funktioner snarere end tabeller og felter som i relationelle databaser. Der blev givet mange eksempler, der viser fordelene ved denne tilgang i forhold til den klassiske. Mange fandt dem ikke overbevisende nok.
I denne artikel vil jeg vise, hvordan et sådant koncept muliggør hurtig og nem balancering af skrivning og læsning i databasen uden nogen ændringer i logikken. Lignende funktionalitet har forsøgt at blive implementeret i moderne kommercielle DBMS (især Oracle og Microsoft SQL Server). I slutningen af artiklen vil jeg vise, hvordan det er gået for dem, mildt sagt, ikke så godt.
Description
Som før vil jeg for bedre forståelse starte beskrivelsen med eksempler. Antag, at vi skal implementere logikken, der returnerer en liste over afdelinger med antallet af medarbejdere i dem og deres samlede løn.
I den funktionelle database vil det se således ud:
CLASS Department ‘Afdeling’;
name ‘Betegnelse’ = DATA STRING[100] (Afdeling);
CLASS Employee 'Medarbejder';
department 'Afdeling' = DATA Department (Employee);
salary 'Løn' = DATA NUMERIC[10,2] (Employee);
countEmployees 'Antal medarbejdere' (Department d) =
GROUP SUM 1 IF department(Employee e) = d;
salarySum 'Samlet løn' (Department d) =
GROUP SUM salary(Employee e) IF department(e) = d;
SELECT name(Department d), countEmployees(d), salarySum(d);
Sværhedsgraden ved at udføre denne forespørgsel i enhver DBMS vil være lig med O(antal medarbejdere), da det for denne beregning er nødvendigt at scanne hele medarbejdertabellen og derefter gruppere dem efter afdeling. Der vil også være et lille (lad os antage, at der er mange flere medarbejdere end afdelinger) tillæg afhængigt af den valgte plan O(log antal medarbejdere) eller O(antal afdelinger) til gruppering og andet.
Det er klart, at overheadomkostningerne ved udførelsen kan variere i forskellige DBMS, men sværhedsgraden ændrer sig ikke.
I den foreslåede implementering vil den funktionelle DBMS generere en enkelt underforespørgsel, der beregner de nødvendige værdier per afdeling, og derefter udføre en JOIN med afdelingstabellen for at hente navnet. Dog kan der ved hver funktionsdeklaration angives en særlig markeringskode kaldet MATERIALIZED. Systemet vil automatisk oprette et tilsvarende felt for hver sådan funktion. Når værdien af funktionen ændres, vil feltets værdi også ændres i samme transaktion. Ved anmodning om denne funktion vil der blive henvist til det allerede forberegnede felt.
Specifikt, hvis MATERIALIZED sættes for funktioner countEmployees og salarySum, tilføjes der to felter i afdelingstabellen, hvor antallet af medarbejdere og deres samlede løn vil blive opbevaret. Ved enhver ændring af medarbejdere, deres lønninger eller deres tilhørsforhold til afdelinger vil systemet automatisk ændre værdierne i disse felter. Den tidligere nævnte forespørgsel vil nu direkte henvise til disse felter og udføres på O(antal afdelinger).
Hvilke begrænsninger? Kun én: en sådan funktion skal have et endeligt antal indgangsværdier, for hvilke dens værdi er defineret. Ellers vil det være umuligt at opbygge en tabel, der opbevarer alle dens værdier, da der ikke kan være en tabel med et uendeligt antal rækker.
Eksempel:
employeesCount 'Antal ansatte med løn > N' (Department d, NUMERIC[10,2] N) =
GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;
Denne funktion er defineret for et uendeligt antal værdier af tallet N (for eksempel passer enhver negativ værdi). Derfor kan MATERIALIZED ikke anvendes på den. Således er dette en logisk, men ikke teknisk begrænsning (dvs. ikke fordi vi ikke kunne implementere det). Udover dette er der ingen begrænsninger. Gruppen kan anvende gruppering, sortering, AND og OR, PARTITION, rekursion osv.
For eksempel kan der i opgave 2.2 fra den tidligere artikel sættes MATERIALIZED på begge funktioner:
købt 'Købt' (Kunde c, Produkt p, INTEGER y) =
GRUPPER SUM sum(Detalje d) HVIS
kunde(ordrer(d)) = c OG
produkt(d) = p OG
udtrækÅr(dato(ordrer(d))) = y MATERIALISERET;
bedømmelse 'Bedømmelse' (Kunde c, Produkt p, INTEGER y) =
PARTITION SUM 1 ORDENS DESC købt(c, p, y), p EFTER c, y MATERIALISERET;
VÆLG kontaktNavn(Kunde c), navn(Produkt p) HVOR bedømmelse(c, p, 1997) < 3;
Systemet opretter automatisk en tabel med nøgletyper Kunde, Product og INTEGER, vil den tilføje to felter til den og opdatere værdierne i disse felter ved enhver ændring. Ved senere anmodninger om disse funktioner vil deres beregning ikke finde sted, og der vil i stedet læses værdier fra de tilsvarende felter.
Ved hjælp af denne mekanisme kan man for eksempel undgå at bruge rekursion (CTE) i forespørgsler. Især kan vi se på grupper, der danner et træ ved hjælp af et child/parent forhold (hver gruppe har et link til sin forælder):
parent = DATA Group (Group);
I den funktionelle database kan rekursionslogikken angives som følger:
niveau (Gruppe barn, Gruppe forælder) = REKURSION 1l HVIS barn ER Gruppe OG forælder == barn
TRIN 2l HVIS forælder == forælder($forælder);
erForælder (Gruppe barn, Gruppe forælder) = SAND HVIS niveau(barn, forælder) MATERIALISERET;
Da funktionen isParent er markeret som MATERIALIZED, vil der blive oprettet en tabel med to nøgler (grupper), hvor feltet isParent kun vil være sandt, hvis den første nøgle er en efterkommer af den anden. Antallet af poster i denne tabel vil være lig med antallet af grupper ganget med den gennemsnitlige dybde af træet. Hvis man for eksempel ønsker at tælle antallet af efterkommere af en bestemt gruppe, kan man kalde denne funktion:
childrenCount (Gruppe g) = GRUPPE SUM 1 HVIS isParent(Gruppe child, g);
Der vil ikke være nogen CTE i SQL-forespørgslen. I stedet vil der være en simpel GROUP BY.
Ved hjælp af denne mekanisme er det også nemt at foretage denormalisering af databasen efter behov:
CLASS Order 'Bestilling';
date 'Dato' = DATA DATE (Bestilling);
CLASS OrderDetail 'Ordrelinje';
order 'Ordre' = DATA Order (OrderDetail);
date 'Dato' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;
Når der kaldes på funktionen date vil der blive læst fra tabellen med ordrelinjer på feltet, hvor der er en indeks. Ved ændring af ordredatoen vil systemet automatisk genberegne den denormaliserede dato i linjen.
Fordele
Hvad er formålet med hele denne mekanisme? I klassiske DBMS kan udvikleren eller DBA'en, uden at skulle omskrive forespørgsler, kun ændre indekser, bestemme statistik og give hints til forespørgselsplanlæggeren om, hvordan de skal udføres (og hints findes kun i kommercielle DBMS'er). Uanset hvor hårdt de prøver, vil de ikke kunne udføre den første forespørgsel i artiklen på O (antal afdelinger) uden at ændre forespørgslerne og tilføje triggers. I det foreslåede skema kan man i udviklingsstadiet ikke tænke på datalagringsstrukturen og hvilke aggregationer der skal bruges. Alt dette kan ændres i realtid under driften.
I praksis ser det således ud. Nogle personer udvikler logikken direkte baseret på den stillede opgave. De forstår ikke algoritmer, deres kompleksitet, eksekveringsplaner, joinkategorier, eller nogen anden teknisk komponent. Disse personer er mere forretningsanalytikere end udviklere. Derefter går alt dette til testning eller drift. Langvarige forespørgsler logges. Når en lang forespørgsel opdages, træffer andre personer (mere tekniske - i praksis DBA'er) beslutningen om at aktivere MATERIALIZED på en mellemfunktion. Dette bremser en smule skrivningen (da der kræves opdatering af et ekstra felt i transaktionen). Men det gør ikke kun denne forespørgsel betydeligt hurtigere, men også alle andre, der bruger denne funktion. Beslutningen om, hvilken funktion der skal materialiseres, træffes forholdsvis nemt. To grundlæggende parametre: antallet af mulige inputværdier (netop så mange poster vil være i den tilsvarende tabel), og hvor ofte den bruges i andre funktioner.
Analoger
I moderne kommercielle DBMS'er er der lignende mekanismer: MATERIALIZED VIEW med FAST REFRESH (Oracle) og INDEXED VIEW (Microsoft SQL Server). I PostgreSQL kan MATERIALIZED VIEW ikke opdateres i transaktionen, men kun ved forespørgsel (med helt strenge begrænsninger), så den ser vi ikke nærmere på. Men de har en række problemer, som betydeligt begrænser deres anvendelse.
For det første kan materialisering kun aktiveres, hvis der allerede er oprettet en almindelig VIEW. Ellers må man omskrive øvrige forespørgsler, der refererer til det nyoprettede view for at bruge denne materialisering. Eller man kan lade alt være som det er, men det vil i det mindste være ineffektivt, hvis der er visse forudberegnede data, men mange forespørgsler benytter dem ikke altid, men beregner dem igen.
For det andet har de en enorm mængde begrænsninger:
Oracle
5.3.8.4 Generelle begrænsninger for hurtig opdatering
Den definerende forespørgsel for det materialiserede view er begrænset som følger:
- Det materialiserede view må ikke indeholde referencer til ikke-repeterende udtryk som
SYSDATEogROWNUM.- Det materialiserede view må ikke indeholde referencer til
RAWellerLONGRAWdatatyper.- Det må ikke indeholde en
SELECTlist subquery.- Det må ikke indeholde analytiske funktioner (for eksempel,
RANK) i denSELECTklausul.- Det må ikke referere til en tabel, som en
XMLIndexindeks er defineret på.- Det må ikke indeholde en
MODELklausul.- Det må ikke indeholde en
HAVINGklausul med en subquery.- Det må ikke indeholde indlejrede forespørgsler, der har
ANY,ALL, ellerNOTEXISTS.- Det må ikke indeholde en
[START WITH …] CONNECT BYklausul.- Det kan ikke indeholde flere detaljetabeller på forskellige steder.
TILCOMMITmaterialiserede visninger kan ikke have fjerndetaljetabeller.- Nederlagte materialiserede visninger skal have en sammenføjning eller aggregat.
- Materialiserede sammenføjningsvisninger og materialiserede aggregatvisninger med en
GRUPPEAFklausul kan ikke vælge fra en indeksorganiseret tabel.5.3.8.5 Begrænsninger for hurtig opdatering af materialiserede visninger med kun sammenføjninger
Definering af forespørgsler for materialiserede visninger med kun sammenføjninger og ingen aggregationer har følgende begrænsninger ved hurtig opdatering:
- Alle begrænsninger fra ««.
- De kan ikke have
GRUPPEAFklausuler eller aggregationer.- Rowids for alle tabeller i
FROMlisten skal fremgå afSELECTlisten over forespørgslen.- Logfiler til materialiserede visninger skal eksistere med rowids for alle basis-tabellerne i
FROMlisten over forespørgslen.- Du kan ikke oprette en hurtigt opdaterbar materialiseret visning fra flere tabeller med enkle sammenføjninger, som inkluderer en objekttypekolonne i
SELECTerklæringen.Derudover vil den opdateringsmetode, du vælger, ikke være optimalt effektiv, hvis:
- Den definierende forespørgsel bruger en ydre sammenføjning, der opfører sig som en indre sammenføjning. Hvis den definierende forespørgsel indeholder en sådan sammenføjning, overvej at omskrive den definierende forespørgsel til at indeholde en indre sammenføjning.
- Listen
SELECTover den materialiserede visning indeholder udtryk på kolonner fra flere tabeller.5.3.8.6 Begrænsninger for hurtig opdatering af materialiserede visninger med aggregationer
Definering af forespørgsler for materialiserede visninger med aggregationer eller sammenføjninger har følgende begrænsninger ved hurtig opdatering:
- Alle begrænsninger fra ««.
Hurtig opdatering understøttes for begge
TILCOMMITogTILEFTERSPØRGSELmaterialiserede visninger, men følgende begrænsninger gælder:
- Alle tabeller i den materialiserede visning skal have logfiler til materialiserede visninger, og logfilerne skal:
- Indeholde alle kolonner fra tabellen, der henvises til i den materialiserede visning.
- Specificere med
ROWIDogINDEHOLDENDENYVALUES.- Specificere
SEQUENCEklausulen, hvis tabellen forventes at have en blanding af indsætninger/ direkte indlæsninger, sletninger og opdateringer.- Kun
SUM,ANTAL,GNSNIT,STDDEV,VARIANS,MINogMAKSIer understøttet for hurtig opdatering.ANTAL(*)skal angives.- Aggregatfunktioner må kun forekomme som den yderste del af udtrykket. Det vil sige, at aggregationer som
GNSNIT(GNSNIT(x))ellerGNSNIT(x)+GNSNIT(x)ikke er tilladt.- For hver aggregation som
GNSNIT(expr), skal det tilsvarendeANTAL(expr)skal være til stede. Oracle anbefaler, atSUM(expr)angives.- Hvis
VARIANS(expr)ellerSTDDEV(expr) angives,ANTAL(expr)ogSUM(expr)skal angives. Oracle anbefaler, atSUM(expr *expr)angives.- Listen
SELECTkolonne i den definierende forespørgsel kan ikke være et komplekst udtryk med kolonner fra flere basis-tabeller. En mulig løsning på dette er at bruge en indlejret materialiseret visning.- Listen
SELECTlisten skal indeholde alleGRUPPEAFkolonner.- Den materialiserede visning er ikke baseret på en eller flere fjerntabeller.
- Hvis du bruger en
CHARdatatype i filterkolonnerne for en log for materialiserede visninger, skal tegnsætterne fra masterstedet og den materialiserede visning være de samme.- Hvis den materialiserede visning har en af følgende, så understøttes hurtig opdatering kun ved konventionelle DML-indlæg og direkte indlæsninger.
- Materialiserede visninger med
MINellerMAKSIaggregationer- Materialiserede visninger, der har
SUM(expr)men ingenANTAL(expr)- Materialiserede visninger uden
ANTAL(*)En sådan materialiseret visning kaldes en materialiseret visning kun til indsættelse.
- En materialiseret visning med
MAKSIellerMINkan hurtigt opdateres efter sletning eller blandede DML-erklæringer, hvis den ikke har enHVORklausul.
Den maksimale/minimale hurtige opdatering efter sletning eller blandet DML har ikke samme opførsel som kun indsættelsescasen. Den sletter og genberegner de maksimale/minimale værdier for de berørte grupper. Du skal være opmærksom på dens præstationsindvirkning.- Materialiserede visninger med navngivne visninger eller underforespørgsler i
FROMklausulen kan hurtigt opdateres, forudsat at visningerne kan samles helt. For information om, hvilke visninger der vil blive samlet, se .- Hvis der ikke er ydre sammenføjninger, kan du have vilkårlige valg og sammenføjninger i
HVORklausul.- Materialiserede aggregatvisninger med ydre joins kan opdateres hurtigt efter konventionel DML og direkte indlæsninger, så længe kun den ydre tabel er blevet ændret. Derudover skal unikke begrænsninger eksistere på join-kolonnerne i den indre join-tabel. Hvis der er ydre joins, skal alle joins være forbundet med
OGog skal bruge lighed (=) operator.- For materialiserede visninger med
CUBE,ROLLUP, grupperingsmængder eller en kombination af dem, gælder følgende restriktioner:
- Listen
SELECTlisten skal indeholde en grupperingsskelner, som kan være enten enGROUPING_IDfunktion på alleGRUPPEAFudtryk ellerGROUPINGfunktioner én for hvertGRUPPEAFudtryk. For eksempel, hvisGRUPPEAFklausulen for den materialiserede visning er «GRUPPEAFCUBE(a, b)«, så skalSELECTlisten indeholde enten «GROUPING_ID(a, b)» eller «GROUPING(a)OGGROUPING(b)» for at den materialiserede visning kan opdateres hurtigt.GRUPPEAFmå ikke resultere i nogen dublerede grupperinger. For eksempel, «GROUP BY a, ROLLUP(a, b)» kan ikke opdateres hurtigt, fordi det resulterer i dublerede grupperinger «(a), (a, b), OG (a)«.5.3.8.7 Restriktioner for Hurtig Opdatering på Materialiserede Visninger med UNION ALL
Materialiserede visninger med
UNIONALLsætopERATOR understøtterOPDATERHURTIGTmuligheden, hvis følgende betingelser er tilfredsstillet:
- Den definerende forespørgsel skal have
UNIONALLoperatoren på det øverste niveau.Listen
UNIONALLoperatoren må ikke være indlejret i en underforespørgsel, med én undtagelse: DenUNIONALLkan være i en underforespørgsel iFROMklausulen, forudsat at den definerende forespørgsel er af formenSELECT * FRA(visning eller underforespørgsel medUNIONALL) som i følgende eksempel:OPRET VISNING view_with_unionall SOM (SELECT c.rowid crid, c.cust_id, 2 umarker FRA kunder c HVOR c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FRA kunder c HVOR c.cust_last_name = 'Jones'); OPRET MATERIALISERET VISNING unionall_inside_view_mv HURTIG OPDATER EFTER BEHOV SOM SELECT * FRA view_with_unionall;Bemærk, at visningen
view_with_unionallopfylder kravene til hurtig opdatering.- Hver forespørgselsblok i
UNIONALLforespørgslen skal opfylde kravene til en hurtig opdaterbar materialiseret visning med aggregationer eller en hurtig opdaterbar materialiseret visning med joins.De relevante materialiserede visningsregistre skal oprettes på tabellerne som krævet for den tilsvarende type af hurtig opdaterbar materialiseret visning.
Bemærk, at Oracle Database også tillader det særlige tilfælde af en enkelt tabel materialiseret visning med kun joins, forudsat atROWIDkolonnen er blevet inkluderet iSELECTlisten og i den materialiserede visningslog. Dette vises i den definerende forespørgsel for visningenview_with_unionall.- Listen
SELECTlisten over hver forespørgsel skal inkludere enUNIONALLmarkør, ogUNIONALLkolonnen skal have en særskilt konstant numerisk eller streng værdi i hverUNIONALLgren. Desuden skal markørkolonnen vises i samme ordensposition iSELECTlisten over hver forespørgselsblok. Se «» for mere information omUNIONALLmarkører.- Nogle funktioner såsom ydre joins, kun indsæt aggregat materialiserede visningsforespørgsler og fjerntabeller understøttes ikke for materialiserede visninger med
UNIONALL. Bemærk dog, at materialiserede visninger, der anvendes i replikation, som ikke indeholder joins eller aggregationer, kan opdateres hurtigt, nårUNIONALLeller fjerntabeller anvendes.- Parameteren for kompatibilitet skal være indstillet til 9.2.0 eller højere for at oprette en hurtig opdaterbar materialiseret visning med
UNIONALL.
Jeg vil ikke såre Oracle-fans, men baseret på deres liste over begrænsninger, ser det ud til, at denne mekanisme ikke er skrevet til generelle tilfælde ved hjælp af en model, men af tusindvis af indere, hvor hver fik tildelt at skrive sin egen gren, og hver gjorde det, de kunne. At bruge denne mekanisme til reel logik er som at gå på en minefelt. Du kan når som helst få en mine, ved at ramme en af de ikke åbenlyse begrænsninger. Hvordan det fungerer er også et separat spørgsmål, men det falder uden for rammerne af denne artikel.
Microsoft SQL Server
Yderligere Krav
Ud over kravene til SET indstillinger og deterministiske funktioner, skal følgende krav opfyldes:
- Brugeren der udfører
CREATE INDEXskal være ejer af visningen.- Når du opretter indekset, skal
IGNORE_DUP_KEYindstillingen være indstillet til OFF (standardindstillingen).- Tabeller skal refereres ved to-delte navne, schema.tablename i visningsdefinitionen.
- Brugerdefinerede funktioner, der refereres i visningen, skal oprettes ved hjælp af
WITH SCHEMABINDINGindstillingen.- Enhver brugerdefineret funktion, der refereres i visningen, skal refereres ved to-delte navne, <schema>.<function>.
- Dataadgangsejendom for en brugerdefineret funktion skal være
NO SQL, og eksterne adgangsejendommene skal væreNO.- Common language runtime (CLR) funktioner kan optræde i select-listen for visningen, men kan ikke være en del af definitionen af den klyngeinficerede indeksnøgle. CLR-funktioner kan ikke vises i WHERE-klausulen for visningen eller i ON-klausulen for en JOIN-operation i visningen.
- CLR-funktioner og metoder for CLR-brugerdefinerede typer, der anvendes i visningsdefinitionen, skal have egenskaberne indstillet som vist i følgende tabel.
Egenskab
NoteDETERMINISTIC = TRUE
Skal erklæres eksplicit som en attribut for Microsoft .NET Framework-metoden.PRECISE = TRUE
Skal erklæres eksplicit som en attribut for .NET Framework-metoden.DATA ADGANG = NO SQL
Bestemt ved at indstille DataAccess-attributten til DataAccessKind.None og SystemDataAccess-attributten til SystemDataAccessKind.None.EKSTERNE ADGANG = NO
Denne egenskab er som standard NO for CLR rutiner.- Visningen skal oprettes ved hjælp af
WITH SCHEMABINDINGindstillingen.- Visningen skal kun referere til basis tabeller, der er i den samme database som visningen. Visningen kan ikke referere til andre visninger.
- SELECT-sætningen i visningsdefinitionen må ikke indeholde følgende Transact-SQL elementer:
ANTAL
ROWSET-funktioner (OPENDATASOURCE,OPENQUERY,OPENROWSET, OGOPENXML)
OUTERjoins (LEFT,RIGHT, ellerFULL)Herledt tabel (defineret ved at angive en
SELECTsætning iFROMklausulen)
Selvjoina
Angive kolonner ved at brugeSELECT *ellerSELECT <table_name>.*
DISTINCT
STDEV,STDEVP,VAR,VARP, ellerGNSNIT
Common table expression (CTE)float1, text, ntext, billede, XML, eller filestream kolonner
Underforespørgsel
OVERklausul, der omfatter rangering eller aggregat vinduesfunktionerFull-text predicates (
CONTAINS,FREETEXT)
SUMfunktion der refererer til et nullable udtryk
ORDER BYCLR brugerdefineret aggregatfunktion
TOP
CUBE,ROLLUP, ellerGROUPING SETSoperatører
MIN,MAKSI
UNION,EXCEPT, ellerINTERSECToperatører
TABLESAMPLETabelvariabler
OUTER APPLYellerCROSS APPLY
PIVOT,UNPIVOTSparse kolonne sæt
Inline (TVF) eller multi-uendelige tabelværdier funktioner (MSTVF)
OFFSET
CHECKSUM_AGG1 Den indekserede visning kan indeholde float kolonner; men sådanne kolonner kan ikke inkluderes i den klyngeinficerede indeksnøgle.
- Hvis
GROUP BYer til stede, skal visningens definition indeholdeCOUNT_BIG(*)og må ikke indeholdeHAVING. DisseGROUP BYbegrænsninger gælder kun for definitionen af den indekserede visning. En forespørgsel kan bruge en indekseret visning i sin udførelsesplan, selvom den ikke opfylder disseGROUP BYbegrænsninger.- Hvis visningsdefinitionen indeholder en
GROUP BYklausul, kan nøgle for det unikke klyngeindeks kun referere til de angivne kolonner i denGROUP BYklausul.
Her kan det ses, at inderne ikke blev tiltrukket, da de besluttede at arbejde efter skemaet 'vi gør lidt, men godt'. Det vil sige, at de har flere miner på marken, men deres placering er mere gennemsigtig. Det, der mest skuffer, er denne begrænsning:
Visningen skal kun referere til basis tabeller, der er i den samme database som visningen. Visningen kan ikke referere til andre visninger.
I vores terminologi betyder det, at funktionen ikke kan henvise til en anden materialiseret funktion. Dette skærer hele ideologien over roden.
Denne begrænsning (og videre i teksten) reducerer også meget brugsmulighederne:
SELECT-sætningen i visningsdefinitionen må ikke indeholde følgende Transact-SQL elementer:
ANTAL
ROWSET-funktioner (OPENDATASOURCE,OPENQUERY,OPENROWSET, OGOPENXML)
OUTERjoins (LEFT,RIGHT, ellerFULL)Herledt tabel (defineret ved at angive en
SELECTsætning iFROMklausulen)
Selvjoina
Angive kolonner ved at brugeSELECT *ellerSELECT <table_name>.*
DISTINCT
STDEV,STDEVP,VAR,VARP, ellerGNSNIT
Common table expression (CTE)float1, text, ntext, billede, XML, eller filestream kolonner
Underforespørgsel
OVERklausul, der omfatter rangering eller aggregat vinduesfunktionerFull-text predicates (
CONTAINS,FREETEXT)
SUMfunktion der refererer til et nullable udtryk
ORDER BYCLR brugerdefineret aggregatfunktion
TOP
CUBE,ROLLUP, ellerGROUPING SETSoperatører
MIN,MAKSI
UNION,EXCEPT, ellerINTERSECToperatører
TABLESAMPLETabelvariabler
OUTER APPLYellerCROSS APPLY
PIVOT,UNPIVOTSparse kolonne sæt
Inline (TVF) eller multi-uendelige tabelværdier funktioner (MSTVF)
OFFSET
CHECKSUM_AGG
OUTER JOINS, UNION, ORDER BY og andet er forbudt. Det ville muligvis være lettere at angive, hvad man må bruge, end hvad man ikke må. Listen ville sandsynligvis være meget kortere.
For at opsummere: et enormt antal begrænsninger i hver (jeg bemærker kommerciel) DBMS vs ingen (bortset fra én logisk, ikke teknisk) i LGPL-teknologien. Det skal dog bemærkes, at det er lidt mere kompliceret at implementere denne mekanisme i relationel logik end i det beskrevne funktionelle.
Implementering
Hvordan fungerer det? PostgreSQL bruges som 'virtuel maskine'. Inden i er der en kompleks algoritme, der beskæftiger sig med opbygningen af forespørgsler. Her er . Og der er ikke blot et stort sæt heuristikker med en masse if’er. Så hvis man har et par måneder til at studere, kan man prøve at forstå arkitekturen.
Fungerer dette effektivt? Ganske effektivt. Desværre er det svært at bevise. Jeg kan kun sige, at hvis man ser på tusindvis af forespørgsler, der findes i store applikationer, så er de i gennemsnit mere effektive end hos en god udvikler. En dygtig SQL-programmør kan skrive enhver forespørgsel mere effektivt, men over tusinde forespørgsler vil han simpelthen ikke have hverken motivation eller tid til at gøre det. Det eneste, jeg kan bruge som bevis for effektiviteten nu, er, at der er flere projekter, der kører på platformen baseret på denne DBMS , som har tusindvis af forskellige MATERIALIZED-funktioner, med tusindvis af brugere og terabyte store databaser med hundreder af millioner poster, der kører på en almindelig to-processors server. Dog kan enhver, der ønsker det, kontrollere/afkræfte effektiviteten ved at downloade og PostgreSQL, logning af SQL-forespørgsler og prøve at ændre logikken og dataene der.
I de følgende artikler vil jeg også fortælle om, hvordan man kan pålægge begrænsninger på funktioner, håndtering af sessioner af ændringer, og meget mere.
Kilde: habr.com
