Balancering af skrivning og læsning i databasen

Balancering af skrivning og læsning i databasen
I den forrige artikel 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 SYSDATE og ROWNUM.
  • Det materialiserede view må ikke indeholde referencer til RAW eller LONG RAW datatyper.
  • Det må ikke indeholde en SELECT list subquery.
  • Det må ikke indeholde analytiske funktioner (for eksempel, RANK) i den SELECT klausul.
  • Det må ikke referere til en tabel, som en XMLIndex indeks er defineret på.
  • Det må ikke indeholde en MODEL klausul.
  • Det må ikke indeholde en HAVING klausul med en subquery.
  • Det må ikke indeholde indlejrede forespørgsler, der har ANY, ALL, eller NOT EXISTS.
  • Det må ikke indeholde en [START WITH …] CONNECT BY klausul.
  • Det kan ikke indeholde flere detaljetabeller på forskellige steder.
  • TIL COMMIT materialiserede visninger kan ikke have fjerndetaljetabeller.
  • Nederlagte materialiserede visninger skal have en sammenføjning eller aggregat.
  • Materialiserede sammenføjningsvisninger og materialiserede aggregatvisninger med en GRUPPE AF klausul 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 «Generelle begrænsninger for hurtig opdatering«.
  • De kan ikke have GRUPPE AF klausuler eller aggregationer.
  • Rowids for alle tabeller i FROM listen skal fremgå af SELECT listen over forespørgslen.
  • Logfiler til materialiserede visninger skal eksistere med rowids for alle basis-tabellerne i FROM listen over forespørgslen.
  • Du kan ikke oprette en hurtigt opdaterbar materialiseret visning fra flere tabeller med enkle sammenføjninger, som inkluderer en objekttypekolonne i SELECT erklæ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 SELECT over 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:

Hurtig opdatering understøttes for begge TIL COMMIT og TIL EFTERSPØRGSEL materialiserede 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 ROWID og INDEHOLDENDE NY VALUES.
    • Specificere SEQUENCE klausulen, hvis tabellen forventes at have en blanding af indsætninger/ direkte indlæsninger, sletninger og opdateringer.

  • Kun SUM, ANTAL, GNSNIT, STDDEV, VARIANS, MIN og MAKSI er 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)) eller GNSNIT(x)+ GNSNIT(x) ikke er tilladt.
  • For hver aggregation som GNSNIT(expr), skal det tilsvarende ANTAL(expr) skal være til stede. Oracle anbefaler, at SUM(expr) angives.
  • Hvis VARIANS(expr) eller STDDEV(expr) angives, ANTAL(expr) og SUM(expr) skal angives. Oracle anbefaler, at SUM(expr *expr) angives.
  • Listen SELECT kolonne 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 SELECT listen skal indeholde alle GRUPPE AF kolonner.
  • Den materialiserede visning er ikke baseret på en eller flere fjerntabeller.
  • Hvis du bruger en CHAR datatype 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 MIN eller MAKSI aggregationer
    • Materialiserede visninger, der har SUM(expr) men ingen ANTAL(expr)
    • Materialiserede visninger uden ANTAL(*)

    En sådan materialiseret visning kaldes en materialiseret visning kun til indsættelse.

  • En materialiseret visning med MAKSI eller MIN kan hurtigt opdateres efter sletning eller blandede DML-erklæringer, hvis den ikke har en HVOR klausul.
    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 FROM klausulen kan hurtigt opdateres, forudsat at visningerne kan samles helt. For information om, hvilke visninger der vil blive samlet, se Oracle Database SQL Sprogreference.
  • Hvis der ikke er ydre sammenføjninger, kan du have vilkårlige valg og sammenføjninger i HVOR klausul.
  • 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 SELECT listen skal indeholde en grupperingsskelner, som kan være enten en GROUPING_ID funktion på alle GRUPPE AF udtryk eller GROUPING funktioner én for hvert GRUPPE AF udtryk. For eksempel, hvis GRUPPE AF klausulen for den materialiserede visning er «GRUPPE AF CUBE(a, b)«, så skal SELECT listen indeholde enten «GROUPING_ID(a, b)» eller «GROUPING(a) OG GROUPING(b)» for at den materialiserede visning kan opdateres hurtigt.
    • GRUPPE AF må 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 UNION ALL sætopERATOR understøtter OPDATER HURTIGT muligheden, hvis følgende betingelser er tilfredsstillet:

  • Den definerende forespørgsel skal have UNION ALL operatoren på det øverste niveau.

    Listen UNION ALL operatoren må ikke være indlejret i en underforespørgsel, med én undtagelse: Den UNION ALL kan være i en underforespørgsel i FROM klausulen, forudsat at den definerende forespørgsel er af formen SELECT * FRA (visning eller underforespørgsel med UNION ALL) 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_unionall opfylder kravene til hurtig opdatering.

  • Hver forespørgselsblok i UNION ALL forespø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 at ROWID kolonnen er blevet inkluderet i SELECT listen og i den materialiserede visningslog. Dette vises i den definerende forespørgsel for visningen view_with_unionall.

  • Listen SELECT listen over hver forespørgsel skal inkludere en UNION ALL markør, og UNION ALL kolonnen skal have en særskilt konstant numerisk eller streng værdi i hver UNION ALL gren. Desuden skal markørkolonnen vises i samme ordensposition i SELECT listen over hver forespørgselsblok. Se «UNION ALL Markør og Forespørgselsomskrivning» for mere information om UNION ALL markører.
  • Nogle funktioner såsom ydre joins, kun indsæt aggregat materialiserede visningsforespørgsler og fjerntabeller understøttes ikke for materialiserede visninger med UNION ALL. Bemærk dog, at materialiserede visninger, der anvendes i replikation, som ikke indeholder joins eller aggregationer, kan opdateres hurtigt, når UNION ALL eller 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 UNION ALL.

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 INDEX skal være ejer af visningen.
  • Når du opretter indekset, skal IGNORE_DUP_KEY indstillingen 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 SCHEMABINDING indstillingen.
  • 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ære NO.
  • 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
    Note

    DETERMINISTIC = 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 SCHEMABINDING indstillingen.
  • 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, OG OPENXML)
    OUTER joins (LEFT, RIGHT, eller FULL)

    Herledt tabel (defineret ved at angive en SELECT sætning i FROM klausulen)
    Selvjoina
    Angive kolonner ved at bruge SELECT * eller SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARP, eller GNSNIT
    Common table expression (CTE)

    float1, text, ntext, billede, XML, eller filestream kolonner
    Underforespørgsel
    OVER klausul, der omfatter rangering eller aggregat vinduesfunktioner

    Full-text predicates (CONTAINS, FREETEXT)
    SUM funktion der refererer til et nullable udtryk
    ORDER BY

    CLR brugerdefineret aggregatfunktion
    TOP
    CUBE, ROLLUP, eller GROUPING SETS operatører

    MIN, MAKSI
    UNION, EXCEPT, eller INTERSECT operatører
    TABLESAMPLE

    Tabelvariabler
    OUTER APPLY eller CROSS APPLY
    PIVOT, UNPIVOT

    Sparse kolonne sæt
    Inline (TVF) eller multi-uendelige tabelværdier funktioner (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Den indekserede visning kan indeholde float kolonner; men sådanne kolonner kan ikke inkluderes i den klyngeinficerede indeksnøgle.

  • Hvis GROUP BY er til stede, skal visningens definition indeholde COUNT_BIG(*) og må ikke indeholde HAVING. Disse GROUP BY begræ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 disse GROUP BY begrænsninger.
  • Hvis visningsdefinitionen indeholder en GROUP BY klausul, kan nøgle for det unikke klyngeindeks kun referere til de angivne kolonner i den GROUP BY klausul.

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, OG OPENXML)
OUTER joins (LEFT, RIGHT, eller FULL)

Herledt tabel (defineret ved at angive en SELECT sætning i FROM klausulen)
Selvjoina
Angive kolonner ved at bruge SELECT * eller SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARP, eller GNSNIT
Common table expression (CTE)

float1, text, ntext, billede, XML, eller filestream kolonner
Underforespørgsel
OVER klausul, der omfatter rangering eller aggregat vinduesfunktioner

Full-text predicates (CONTAINS, FREETEXT)
SUM funktion der refererer til et nullable udtryk
ORDER BY

CLR brugerdefineret aggregatfunktion
TOP
CUBE, ROLLUP, eller GROUPING SETS operatører

MIN, MAKSI
UNION, EXCEPT, eller INTERSECT operatører
TABLESAMPLE

Tabelvariabler
OUTER APPLY eller CROSS APPLY
PIVOT, UNPIVOT

Sparse 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 kildekoden. 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 ERP-systemer, 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 platformen og PostgreSQL, aktivere 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

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster