Balancering af skrivninger og læsninger i databasen

Balancering af skrivninger og læsninger i databasen
I det foregående artiklen Jeg beskrev konceptet og implementeringen af ​​en database bygget på basis af funktioner, frem for tabeller og felter som i relationelle databaser. Det gav mange eksempler, der viste fordelene ved denne fremgangsmåde frem for den klassiske. Mange fandt dem ikke overbevisende nok.

I denne artikel vil jeg vise, hvordan dette koncept giver dig mulighed for hurtigt og bekvemt at balancere skrivninger og læsninger til databasen uden nogen ændring i driftslogikken. Lignende funktionalitet er blevet forsøgt implementeret i moderne kommercielle DBMS'er (især Oracle og Microsoft SQL Server). Til sidst i artiklen vil jeg vise, at det, de gjorde, mildt sagt ikke fungerede særlig godt.

beskrivelse

Som før vil jeg for bedre forståelse starte beskrivelsen med eksempler. Lad os sige, at vi skal implementere logik, der vil returnere en liste over afdelinger med antallet af medarbejdere i dem og deres samlede løn.

I en funktionel database vil det se sådan ud:

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);

Kompleksiteten ved at udføre denne forespørgsel i ethvert DBMS vil svare til O (antal ansatte)fordi denne beregning kræver, at man scanner hele tabellen over medarbejdere og derefter grupperer dem efter afdeling. Der vil også være nogle små (vi mener at der er mange flere ansatte end afdelinger) tillæg afhængig af den valgte plan O (log antal ansatte) eller O (antal afdelinger) til gruppering og så videre.

Det er klart, at udførelsesomkostningerne kan være forskellige i forskellige DBMS'er, men kompleksiteten vil ikke ændre sig på nogen måde.

I den foreslåede implementering vil den funktionelle DBMS generere en underforespørgsel, der beregner de nødvendige værdier for afdelingen og derefter lave en JOIN med afdelingstabellen for at få navnet. For hver funktion er det dog muligt at indstille en speciel MATERIALISERET markør ved deklarering. Systemet vil automatisk oprette et tilsvarende felt for hver sådan funktion. Når værdien af ​​en funktion ændres, ændres feltets værdi også i samme transaktion. Når du får adgang til denne funktion, får du adgang til det forudberegnede felt.

Især hvis du indstiller MATERIALISERET for funktioner tæller medarbejdere и lønSum, så tilføjes to felter til tabellen med listen over afdelinger, som gemmer antallet af medarbejdere og deres samlede løn. Når der er en ændring i medarbejdere, deres løn eller afdelingstilknytning, vil systemet automatisk ændre værdierne for disse felter. Ovenstående forespørgsel vil få direkte adgang til disse felter og vil blive udført i O (antal afdelinger).

Hvad er begrænsningerne? Kun én ting: en sådan funktion skal have et begrænset antal inputværdier, som dens værdi er defineret for. Ellers vil det være umuligt at bygge en tabel, der gemmer alle dens værdier, da der ikke kan være en tabel med et uendeligt antal rækker.

Eksempel:

employeesCount ‘Количество сотрудников с зарплатой > 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 N (for eksempel er enhver negativ værdi egnet). Derfor kan du ikke sætte MATERIALIZED på den. Så dette er en logisk begrænsning, ikke en teknisk (det vil sige ikke fordi vi ikke kunne implementere den). Ellers er der ingen begrænsninger. Du kan bruge grupperinger, sortering, OG og ELLER, PARTITION, rekursion osv.

For eksempel, i opgave 2.2 i den forrige artikel, kan du sætte MATERIALIZED på begge funktioner:

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;

Systemet selv vil oprette en tabel med typetaster Kunden, Produkt и HELTAL, tilføjer to felter til det og opdaterer feltværdierne i dem med eventuelle ændringer. Når der foretages yderligere opkald til disse funktioner, vil de ikke blive beregnet, men værdierne vil snarere blive læst fra de tilsvarende felter.

Ved at bruge denne mekanisme kan du for eksempel slippe af med rekursioner (CTE) i forespørgsler. Overvej især grupper, der danner et træ ved hjælp af barnet/forælder-forholdet (hver gruppe har et link til sin forælder):

parent = DATA Group (Group);

I en funktionel database kan rekursionslogik specificeres som følger:

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;

Siden for funktionen er Forælder er markeret MATERIALISERET, så vil der blive oprettet en tabel med to nøgler (grupper) til den, hvor feltet er Forælder vil kun være sandt, hvis den første nøgle er et underordnet af den anden. Antallet af poster i denne tabel vil være lig med antallet af grupper ganget med træets gennemsnitlige dybde. Hvis du for eksempel skal tælle antallet af efterkommere af en bestemt gruppe, kan du bruge denne funktion:

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

Der vil ikke være nogen CTE i SQL-forespørgslen. I stedet vil der være en simpel GROUP BY.

Ved at bruge denne mekanisme kan du også nemt denormalisere databasen, hvis det er nødvendigt:

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

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

Når du kalder en funktion dato for ordrelinjen vil det felt, der er indeks for, blive aflæst fra tabellen med ordrelinjer. Når ordredatoen ændres, vil systemet selv automatisk genberegne den denormaliserede dato i linjen.

Fordele

Hvad er hele denne mekanisme til? I klassiske DBMS'er, uden at omskrive forespørgsler, kan en udvikler eller DBA kun ændre indekser, bestemme statistikker og fortælle forespørgselsplanlæggeren, hvordan de skal udføres (og TIP er kun tilgængelige i kommercielle DBMS'er). Uanset hvor meget de prøver, vil de ikke være i stand til at fuldføre den første forespørgsel i artiklen i O (antal afdelinger) uden at ændre forespørgsler eller tilføje triggere. I den foreslåede ordning behøver du på udviklingsstadiet ikke at tænke på datalagringsstrukturen og hvilke aggregeringer, der skal bruges. Alt dette kan nemt ændres i farten, direkte i drift.

I praksis ser det sådan ud. Nogle mennesker udvikler logik direkte baseret på den aktuelle opgave. De forstår ikke algoritmer og deres kompleksitet, heller ikke eksekveringsplaner, eller typer af joinforbindelser eller nogen anden teknisk komponent. Disse mennesker er mere forretningsanalytikere end udviklere. Derefter går alt dette til test eller drift. Aktiverer logning af langvarige forespørgsler. Når en lang forespørgsel detekteres, beslutter andre personer (mere tekniske - i det væsentlige DBA) at aktivere MATERIALIZED på en eller anden mellemfunktion. Dette sænker optagelsen lidt (da det kræver opdatering af et ekstra felt i transaktionen). Imidlertid er ikke kun denne forespørgsel markant fremskyndet, men også alle andre, der bruger denne funktion. Samtidig er det relativt nemt at beslutte, hvilken funktion der skal realiseres. To hovedparametre: antallet af mulige inputværdier (dette er hvor mange poster der vil være i den tilsvarende tabel), og hvor ofte det bruges i andre funktioner.

analoger

Moderne kommercielle DBMS'er har lignende mekanismer: MATERIALISERET VISNING med FAST REFRESH (Oracle) og INDEXED VIEW (Microsoft SQL Server). I PostgreSQL kan MATERIALIZED VIEW ikke opdateres i en transaktion, men kun på anmodning (og endda med meget strenge begrænsninger), så vi overvejer det ikke. Men de har flere problemer, der begrænser deres brug betydeligt.

For det første kan du kun aktivere materialisering, hvis du allerede har oprettet en almindelig VIEW. Ellers bliver du nødt til at omskrive de resterende anmodninger for at få adgang til den nyoprettede visning for at bruge denne materialisering. Eller lad alt være som det er, men det vil i det mindste være ineffektivt, hvis der er visse allerede forudberegnet data, men mange forespørgsler bruger det ikke altid, men genberegner det.

For det andet har de et stort antal begrænsninger:

Oracle

5.3.8.4 Generelle begrænsninger for hurtig opdatering

Den definerende forespørgsel for den materialiserede visning er begrænset som følger:

  • Den materialiserede visning må ikke indeholde referencer til ikke-gentagende udtryk som f.eks SYSDATE , ROWNUM.
  • Det materialiserede syn må ikke indeholde referencer til RAW or LONG RAW datatyper.
  • Den kan ikke indeholde en SELECT liste underforespørgsel.
  • Det kan ikke indeholde analytiske funktioner (f.eks. RANK) I SELECT klausul.
  • Den kan ikke referere til en tabel, hvorpå en XMLIndex indeks er defineret.
  • Den kan ikke indeholde en MODEL klausul.
  • Den kan ikke indeholde en HAVING klausul med en underforespørgsel.
  • Den kan ikke indeholde indlejrede forespørgsler, der har ANY, ALL eller NOT EXISTS.
  • Den kan ikke indeholde en [START WITH …] CONNECT BY klausul.
  • Den kan ikke indeholde flere detaljetabeller på forskellige steder.
  • ON COMMIT materialiserede visninger kan ikke have eksterne detaljetabeller.
  • Indlejrede materialiserede visninger skal have en joinforbindelse eller aggregeret.
  • Materialiserede sammenføjningsvisninger og materialiserede aggregerede visninger med en GROUP BY 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 sammenkædninger og ingen aggregater har følgende begrænsninger for hurtig opdatering:

  • Alle restriktioner fra «Generelle begrænsninger for hurtig opdatering".
  • Det kan de ikke have GROUP BY klausuler eller aggregater.
  • Rowids af alle tabellerne i FROM listen skal fremgå af SELECT listen over forespørgslen.
  • Materialiserede visningslogfiler skal eksistere med rækker for alle basistabellerne i FROM listen over forespørgslen.
  • Du kan ikke oprette en hurtig genopfriskende materialiseret visning fra flere tabeller med simple joinforbindelser, der inkluderer en objekttypekolonne i SELECT udmelding.

Desuden vil den opdateringsmetode, du vælger, ikke være optimalt effektiv, hvis:

  • Den definerende forespørgsel bruger en ydre joinforbindelse, der opfører sig som en indre joinforbindelse. Hvis den definerende forespørgsel indeholder en sådan joinforbindelse, kan du overveje at omskrive den definerende forespørgsel til at indeholde en indre joinforbindelse.
  • SELECT listen over den materialiserede visning indeholder udtryk på kolonner fra flere tabeller.

5.3.8.6 Begrænsninger for hurtig opdatering af materialiserede visninger med aggregater

Definering af forespørgsler for materialiserede visninger med aggregater eller joinforbindelser har følgende begrænsninger for hurtig opdatering:

Hurtig opdatering understøttes for begge ON COMMIT , ON DEMAND materialiserede synspunkter, dog gælder følgende begrænsninger:

  • Alle tabeller i den materialiserede visning skal have materialiserede visningslogfiler, og de materialiserede visningslogfiler skal:
    • Indeholder alle kolonner fra tabellen, der henvises til i den materialiserede visning.
    • Angiv med ROWID , INCLUDING NEW VALUES.
    • Angiv SEQUENCE klausul, hvis tabellen forventes at have en blanding af indsættelser/direkte indlæsninger, sletninger og opdateringer.

  • Kun SUM, COUNT, AVG, STDDEV, VARIANCE, MIN , MAX understøttes til hurtig opdatering.
  • COUNT(*) skal specificeres.
  • Aggregerede funktioner må kun forekomme som den yderste del af udtrykket. Det vil sige aggregater som f.eks AVG(AVG(x)) or AVG(x)+ AVG(x) er ikke tilladt.
  • For hvert aggregat som f.eks AVG(expr), det tilsvarende COUNT(expr) skal være til stede. Det anbefaler Oracle SUM(expr) være specificeret.
  • If VARIANCE(expr) or STDDEV(expr) er angivet, COUNT(expr) , SUM(expr) skal specificeres. Det anbefaler Oracle SUM(expr *expr) være specificeret.
  • SELECT kolonne i den definerende forespørgsel kan ikke være et komplekst udtryk med kolonner fra flere basistabeller. En mulig løsning på dette er at bruge en indlejret materialiseret visning.
  • SELECT listen skal indeholde alle GROUP BY kolonner.
  • Den materialiserede visning er ikke baseret på en eller flere fjerntabeller.
  • Hvis du bruger en CHAR datatype i filterkolonnerne i en materialiseret visningslog, skal tegnsættene for masterwebstedet og den materialiserede visning være de samme.
  • Hvis den materialiserede visning har en af ​​følgende, understøttes hurtig opdatering kun på konventionelle DML-indlæg og direkte indlæsninger.
    • Materialiserede udsigter med MIN or MAX aggregater
    • Materialiserede synspunkter som har SUM(expr) men nej COUNT(expr)
    • Materialiserede udsigter uden COUNT(*)

    En sådan materialiseret visning kaldes en indsættelses-kun materialiseret visning.

  • Et materialiseret syn med MAX or MIN kan hurtigt opdateres efter sletning eller blandede DML-sætninger, hvis den ikke har en WHERE klausul.
    Maks/min hurtig opdatering efter sletning eller blandet DML har ikke den samme adfærd som tilfældet med kun indsættelse. Den sletter og genberegner max/min værdierne for de berørte grupper. Du skal være opmærksom på dens præstationspåvirkning.
  • Materialiserede visninger med navngivne visninger eller underforespørgsler i FROM klausulen kan hurtigt opdateres, forudsat at synspunkterne kan fusioneres fuldstændigt. For information om, hvilke visninger der vil fusionere, se Oracle Database SQL Language Reference.
  • Hvis der ikke er nogen ydre joins, kan du have vilkårlige valg og joins i WHERE klausul.
  • Materialiserede aggregerede visninger med ydre sammenføjninger kan hurtigt opdateres efter konventionel DML og direkte belastninger, forudsat at kun den ydre tabel er blevet ændret. Der skal også eksistere unikke begrænsninger på joinkolonnerne i den indre jointabel. Hvis der er ydre sammenføjninger, skal alle sammenføjninger forbindes med ANDs og skal bruge ligheden (=) operatør.
  • For materialiserede synspunkter med CUBE, ROLLUP, grupperingssæt eller sammenkædning af dem, gælder følgende begrænsninger:
    • SELECT listen skal indeholde grupperingskendetegn, der enten kan være en GROUPING_ID funktion på alle GROUP BY udtryk eller GROUPING funktioner en for hver GROUP BY udtryk. For eksempel, hvis GROUP BY klausulen i den materialiserede opfattelse er "GROUP BY CUBE(a, b)", derefter SELECT listen skal indeholde enten "GROUPING_ID(a, b)» eller «GROUPING(a) AND GROUPING(b)» for at den materialiserede visning hurtigt kan genopfriskes.
    • GROUP BY bør ikke resultere i duplikerede grupperinger. For eksempel, "GROUP BY a, ROLLUP(a, b)" kan ikke hurtigt opdateres, fordi det resulterer i duplikerede grupperinger "(a), (a, b), AND (a)".

5.3.8.7 Begrænsninger for hurtig opdatering af materialiserede visninger med UNION ALL

Materialiserede synspunkter med UNION ALL sæt operatørstøtte REFRESH FAST mulighed, hvis følgende betingelser er opfyldt:

  • Den definerende forespørgsel skal have UNION ALL operatør på øverste niveau.

    UNION ALL operator kan ikke indlejres i en underforespørgsel, med én undtagelse: The UNION ALL kan være i en underforespørgsel i FROM klausul, forudsat at den definerende forespørgsel er af formen SELECT * FROM (se eller underforespørgsel med UNION ALL) som i følgende eksempel:

    CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM kunder c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM kunder c WHERE c.cust_last_name = 'Jones'); OPRET MATERIALISERET VISNING unionall_inside_view_mv OPFRASKER HURTIGT PÅ DEMAND SOM SELECT * FRA view_with_unionall;
    

    Bemærk at udsigten view_with_unionall opfylder kravene til hurtig opdatering.

  • Hver forespørgselsblok i UNION ALL forespørgslen skal opfylde kravene til en hurtigt genopfriskende materialiseret visning med aggregater eller en hurtig genopfriskende materialiseret visning med sammenføjninger.

    De relevante materialiserede visningslogfiler skal oprettes på tabellerne efter behov for den tilsvarende type hurtigt genopfriskende materialiseret visning.
    Bemærk, at Oracle-databasen også tillader det specielle tilfælde af en enkelt tabelmaterialiseret visning med sammenføjninger kun forudsat ROWID kolonne er inkluderet i SELECT liste og i den materialiserede visningslog. Dette vises i visningens definerende forespørgsel view_with_unionall.

  • SELECT listen over hver forespørgsel skal indeholde en UNION ALL markør og UNION ALL kolonne skal have en særskilt konstant numerisk eller strengværdi i hver UNION ALL afdeling. Yderligere skal markørsøjlen vises i samme ordensposition i SELECT liste over hver forespørgselsblok. Se "UNION ALL Marker og forespørgsel omskrivning» for mere information vedr UNION ALL markører.
  • Nogle funktioner som f.eks. ydre sammenføjninger, samlede materialiserede visningsforespørgsler, der kun kan indsættes, og eksterne tabeller understøttes ikke for materialiserede visninger med UNION ALL. Bemærk dog, at materialiserede visninger, der bruges i replikering, og som ikke indeholder joinforbindelser eller aggregater, hurtigt kan opdateres, når UNION ALL eller der bruges fjernborde.
  • Kompatibilitetsinitieringsparameteren skal indstilles til 9.2.0 eller højere for at skabe en hurtig genopfriskende materialiseret visning med UNION ALL.

Jeg ønsker ikke at fornærme Oracle-fans, men at dømme efter deres liste over restriktioner, ser det ud til, at denne mekanisme ikke blev skrevet i det generelle tilfælde, ved at bruge en form for model, men af ​​tusindvis af indere, hvor alle fik mulighed for at skriv deres egen gren, og hver af dem gjorde, hvad han kunne og gjorde. At bruge denne mekanisme til ægte logik er som at gå gennem et minefelt. Du kan få en mine til enhver tid ved at ramme en af ​​de ikke-oplagte restriktioner. Hvordan det virker er også et særskilt spørgsmål, men det ligger uden for denne artikels rammer.

Microsoft SQL Server

Yderligere krav

Ud over SET-mulighederne og deterministiske funktionskrav skal følgende krav være opfyldt:

  • Brugeren der udfører CREATE INDEX skal være ejer af udsigten.
  • Når du opretter indekset, vil IGNORE_DUP_KEY indstillingen skal være indstillet til FRA (standardindstillingen).
  • Tabeller skal refereres med todelte navne, skema.bordnavn i visningsdefinitionen.
  • Brugerdefinerede funktioner, der refereres til i visningen, skal oprettes ved at bruge WITH SCHEMABINDING valgmulighed.
  • Alle brugerdefinerede funktioner, der refereres til i visningen, skal refereres til med todelte navne, ..
  • Dataadgangsegenskaben for en brugerdefineret funktion skal være NO SQL, og ekstern adgang egenskab skal være NO.
  • Common Language Runtime (CLR)-funktioner kan vises i visningens udvalgte liste, men kan ikke være en del af definitionen af ​​den klyngede indeksnøgle. CLR-funktioner kan ikke vises i WHERE-udtrykket i visningen eller ON-udtrykket i en JOIN-operation i visningen.
  • CLR-funktioner og -metoder for CLR-brugerdefinerede typer, der bruges i visningsdefinitionen, skal have egenskaberne indstillet som vist i følgende tabel.

    Ejendom
    Bemærk

    DETERMINISTISK = SAND
    Skal udtrykkeligt erklæres som en attribut for Microsoft .NET Framework-metoden.

    PRÆCIS = SAND
    Skal erklæres eksplicit som en attribut for .NET Framework-metoden.

    DATAADGANG = INGEN SQL
    Bestemmes ved at sætte DataAccess-attributten til DataAccessKind.None og SystemDataAccess-attributten til SystemDataAccessKind.None.

    EKSTERN ADGANG = NEJ
    Denne egenskab er som standard NEJ for CLR-rutiner.

  • Visningen skal oprettes ved at bruge WITH SCHEMABINDING valgmulighed.
  • Visningen må kun referere til basistabeller, der er i den samme database som visningen. Visningen kan ikke referere til andre synspunkter.
  • SELECT-sætningen i visningsdefinitionen må ikke indeholde følgende Transact-SQL-elementer:

    COUNT
    ROWSET funktioner (OPENDATASOURCE, OPENQUERY, OPENROWSET, OG OPENXML)
    OUTER slutter sig til (LEFT, RIGHT eller FULL)

    Afledt tabel (defineret ved at angive en SELECT erklæring i FROM klausul)
    Selv tilslutter sig
    Angivelse af kolonner ved hjælp af SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARP eller AVG
    Fælles tabeludtryk (CTE)

    flyde1, tekst, ntekst, billede, XML eller filstream kolonner
    Underforespørgsel
    OVER klausul, som inkluderer rangering eller aggregerede vinduesfunktioner

    Fuldtekstprædikater (CONTAINS, FREETEXT)
    SUM funktion, der refererer til et nullbart udtryk
    ORDER BY

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

    MIN, MAX
    UNION, EXCEPT eller INTERSECT Operatører
    TABLESAMPLE

    Tabel variabler
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Sparsomme søjlesæt
    Inline (TVF) eller multi-statement table-valued functions (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Den indekserede visning kan indeholde flyde søjler; sådanne kolonner kan dog ikke inkluderes i den klyngede indeksnøgle.

  • If GROUP BY er til stede, skal VIEW-definitionen 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 restriktioner.
  • Hvis visningsdefinitionen indeholder en GROUP BY klausul, kan nøglen til det unikke klyngede indeks kun referere til de kolonner, der er angivet i GROUP BY klausul.

Det er tydeligt her, at indianerne ikke var involveret, da de besluttede at gøre det i henhold til ordningen "vi vil gøre lidt, men godt." Det vil sige, at de har flere miner på marken, men deres placering er mere gennemsigtig. Det mest skuffende er denne begrænsning:

Visningen må kun referere til basistabeller, der er i den samme database som visningen. Visningen kan ikke referere til andre synspunkter.

I vores terminologi betyder det, at en funktion ikke kan få adgang til en anden materialiseret funktion. Dette skærer ned på al ideologi i opløbet.
Også denne begrænsning (og længere i teksten) reducerer anvendelsestilfældene betydeligt:

SELECT-sætningen i visningsdefinitionen må ikke indeholde følgende Transact-SQL-elementer:

COUNT
ROWSET funktioner (OPENDATASOURCE, OPENQUERY, OPENROWSET, OG OPENXML)
OUTER slutter sig til (LEFT, RIGHT eller FULL)

Afledt tabel (defineret ved at angive en SELECT erklæring i FROM klausul)
Selv tilslutter sig
Angivelse af kolonner ved hjælp af SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARP eller AVG
Fælles tabeludtryk (CTE)

flyde1, tekst, ntekst, billede, XML eller filstream kolonner
Underforespørgsel
OVER klausul, som inkluderer rangering eller aggregerede vinduesfunktioner

Fuldtekstprædikater (CONTAINS, FREETEXT)
SUM funktion, der refererer til et nullbart udtryk
ORDER BY

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

MIN, MAX
UNION, EXCEPT eller INTERSECT Operatører
TABLESAMPLE

Tabel variabler
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Sparsomme søjlesæt
Inline (TVF) eller multi-statement table-valued functions (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY og andre er forbudt. Det kunne have været lettere at specificere, hvad der kunne bruges frem for hvad der ikke kunne bruges. Listen ville sandsynligvis være meget mindre.

For at opsummere: et enormt sæt begrænsninger i hver (lad os bemærke kommerciel) DBMS vs ingen (med undtagelse af en logisk, ikke teknisk) i LGPL-teknologi. Det skal dog bemærkes, at implementering af denne mekanisme i relationel logik er noget sværere end i den beskrevne funktionelle logik.

implementering

Hvordan det virker? PostgreSQL bruges som en "virtuel maskine". Der er en kompleks algoritme indeni, der bygger forespørgsler. Her kildekode. Og der er ikke bare et stort sæt heuristik med en masse hvis. Så hvis du har et par måneder til at studere, kan du prøve at forstå arkitektur.

Virker det effektivt? Ganske effektivt. Det er desværre svært at bevise. Jeg kan kun sige, at hvis du overvejer de tusindvis af forespørgsler, der findes i store applikationer, så er de i gennemsnit mere effektive end en god udviklers. En fremragende SQL-programmør kan skrive enhver forespørgsel mere effektivt, men med tusind forespørgsler vil han simpelthen ikke have motivationen eller tiden til at gøre det. Det eneste, jeg nu kan nævne som bevis på effektivitet, er, at flere projekter arbejder på platformen bygget på dette DBMS ERP-systemer, som har tusindvis af forskellige MATERIALISEREDE funktioner, med tusindvis af brugere og terabyte databaser med hundredvis af millioner af poster, der kører på en almindelig to-processor server. Alle kan dog kontrollere/afvise effektiviteten ved at downloade platform og PostgreSQL, tændt logger SQL-forespørgsler og forsøger at ændre logikken og dataene der.

I de følgende artikler vil jeg også fortælle om, hvordan du kan sætte begrænsninger på funktioner, arbejde med forandringssessioner og meget mere.

Kilde: www.habr.com

Tilføj en kommentar