Balanceren tussen schrijven en lezen in een database

Balanceren tussen schrijven en lezen in een database
In de vorige статье Ik beschreef het concept en de implementatie van een database die is gebouwd op basis van functies, in plaats van tabellen en velden zoals in relationele databases. Het leverde veel voorbeelden op die de voordelen van deze aanpak ten opzichte van de klassieke aanpak lieten zien. Velen vonden ze niet overtuigend genoeg.

In dit artikel laat ik zien hoe u met dit concept snel en gemakkelijk schrijf- en leesbewerkingen naar de database kunt balanceren zonder enige wijziging in de bedieningslogica. Er is geprobeerd soortgelijke functionaliteit te implementeren in moderne commerciële DBMS'en (in het bijzonder Oracle en Microsoft SQL Server). Aan het einde van het artikel zal ik laten zien dat wat ze deden, op zijn zachtst gezegd, niet zo goed uitpakte.

beschrijving

Voor een beter begrip zal ik, net als voorheen, de beschrijving beginnen met voorbeelden. Laten we zeggen dat we logica moeten implementeren die een lijst met afdelingen retourneert met het aantal werknemers daarin en hun totale salaris.

In een functionele database zou het er als volgt uitzien:

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

De complexiteit van het uitvoeren van deze query in elk DBMS zal gelijk zijn aan O(aantal medewerkers)omdat deze berekening vereist dat de hele tabel met medewerkers wordt gescand en vervolgens per afdeling wordt gegroepeerd. Afhankelijk van het gekozen plan zal er ook sprake zijn van een kleine (we denken dat er veel meer medewerkers zijn dan afdelingen). O(logboek aantal medewerkers) of O(aantal afdelingen) voor groeperen enzovoort.

Het is duidelijk dat de uitvoeringsoverhead in verschillende DBMS'en verschillend kan zijn, maar de complexiteit zal op geen enkele manier veranderen.

In de voorgestelde implementatie zal het functionele DBMS één subquery genereren die de vereiste waarden voor de afdeling berekent, en vervolgens een JOIN maken met de afdelingstabel om de naam te verkrijgen. Voor elke functie is het echter mogelijk om bij het declareren een speciale MATERIALIZED-markering in te stellen. Het systeem maakt voor elke dergelijke functie automatisch een overeenkomstig veld aan. Wanneer u de waarde van een functie wijzigt, verandert in dezelfde transactie ook de waarde van het veld. Wanneer u deze functie opent, wordt het vooraf berekende veld geopend.

In het bijzonder als u MATERIALIZED instelt voor functies tellenWerknemers и salarisSom, dan worden er twee velden toegevoegd aan de tabel met de lijst met afdelingen, waarin het aantal werknemers en hun totale salaris worden opgeslagen. Telkens wanneer er een verandering plaatsvindt in werknemers, hun salarissen of afdelingen, zal het systeem automatisch de waarden van deze velden wijzigen. De bovenstaande zoekopdracht heeft rechtstreeks toegang tot deze velden en wordt uitgevoerd in O(aantal afdelingen).

Wat zijn de beperkingen? Slechts één ding: zo’n functie moet een eindig aantal invoerwaarden hebben waarvoor de waarde ervan is gedefinieerd. Anders zal het onmogelijk zijn om een ​​tabel te bouwen die al zijn waarden opslaat, aangezien er geen tabel kan zijn met een oneindig aantal rijen.

Voorbeeld:

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

Deze functie is gedefinieerd voor een oneindig aantal waarden van N (elke negatieve waarde is bijvoorbeeld geschikt). Daarom kun je er geen MATERIALIZED op plaatsen. Dit is dus een logische beperking, geen technische beperking (dat wil zeggen, niet omdat we deze niet konden implementeren). Anders zijn er geen beperkingen. U kunt groeperingen, sortering, EN en OF, PARTITIE, recursie, enz. gebruiken.

In probleem 2.2 van het vorige artikel kun je bijvoorbeeld MATERIALIZED op beide functies zetten:

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;

Het systeem zelf maakt één tabel met typesleutels , Product и GEHEEL GETAL, voegt er twee velden aan toe en werkt de veldwaarden daarin bij met eventuele wijzigingen. Wanneer er verdere oproepen naar deze functies worden gedaan, worden deze niet berekend, maar worden de waarden uit de overeenkomstige velden gelezen.

Met dit mechanisme kunt u bijvoorbeeld recursies (CTE) in query's verwijderen. Denk in het bijzonder aan groepen die een boom vormen met behulp van de kind-ouderrelatie (elke groep heeft een link naar zijn ouder):

parent = DATA Group (Group);

In een functionele database kan recursielogica als volgt worden gespecificeerd:

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;

Omdat voor de functie isOuder is gemarkeerd als MATERIALIZED, dan wordt er een tabel met twee sleutels (groepen) voor gemaakt, waarin het veld isOuder zal alleen waar zijn als de eerste sleutel een kind is van de tweede. Het aantal vermeldingen in deze tabel is gelijk aan het aantal groepen vermenigvuldigd met de gemiddelde diepte van de boom. Als u bijvoorbeeld het aantal nakomelingen van een bepaalde groep wilt tellen, kunt u deze functie gebruiken:

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

Er zal geen CTE in de SQL-query voorkomen. In plaats daarvan zal er een eenvoudige GROUP BY zijn.

Met dit mechanisme kunt u de database indien nodig ook eenvoudig denormaliseren:

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

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

Bij het aanroepen van een functie gegevens voor de orderregel wordt uit de tabel met orderregels het veld gelezen waarvoor een index bestaat. Wanneer de besteldatum verandert, zal het systeem zelf automatisch de gedenormaliseerde datum in de regel herberekenen.

Voordelen

Waar is dit hele mechanisme voor? In klassieke DBMS's kan een ontwikkelaar of DBA, zonder query's te herschrijven, alleen indexen wijzigen, statistieken bepalen en de queryplanner vertellen hoe deze moet worden uitgevoerd (en HINT's zijn alleen beschikbaar in commerciële DBMS's). Hoe hard ze ook proberen, ze zullen de eerste vraag in het artikel niet kunnen voltooien O (aantal afdelingen) zonder zoekopdrachten te wijzigen of triggers toe te voegen. In het voorgestelde schema hoeft u in de ontwikkelingsfase niet na te denken over de gegevensopslagstructuur en welke aggregaties u moet gebruiken. Dit alles kan eenvoudig en direct tijdens gebruik worden gewijzigd.

In de praktijk ziet het er zo uit. Sommige mensen ontwikkelen logica rechtstreeks op basis van de taak die voorhanden is. Ze begrijpen geen algoritmen en hun complexiteit, noch uitvoeringsplannen, noch soorten joins, noch enige andere technische component. Deze mensen zijn meer bedrijfsanalisten dan ontwikkelaars. Vervolgens wordt dit allemaal getest of in bedrijf gesteld. Maakt het loggen van langlopende zoekopdrachten mogelijk. Wanneer een lange zoekopdracht wordt gedetecteerd, besluiten andere mensen (meer technisch - in wezen DBA) om MATERIALIZED in te schakelen voor een tussenliggende functie. Dit vertraagt ​​de registratie een beetje (aangezien hiervoor een extra veld in de transactie moet worden bijgewerkt). Niet alleen deze zoekopdracht wordt echter aanzienlijk versneld, maar ook alle andere die deze functie gebruiken. Tegelijkertijd is het relatief eenvoudig om te beslissen welke functie moet worden gerealiseerd. Twee hoofdparameters: het aantal mogelijke invoerwaarden (dit is hoeveel records er in de bijbehorende tabel staan) en hoe vaak het in andere functies wordt gebruikt.

analogen

Moderne commerciële DBMS'en hebben vergelijkbare mechanismen: GEMATERIALISEERDE VIEW met FAST REFRESH (Oracle) en INDEXED VIEW (Microsoft SQL Server). In PostgreSQL kan MATERIALIZED VIEW niet in een transactie worden bijgewerkt, maar alleen op verzoek (en zelfs met zeer strikte beperkingen), dus we houden er geen rekening mee. Maar ze hebben verschillende problemen die het gebruik ervan aanzienlijk beperken.

Ten eerste kun je materialisatie alleen inschakelen als je al een reguliere VIEW hebt gemaakt. Anders moet u de resterende aanvragen herschrijven om toegang te krijgen tot de nieuw gemaakte weergave om deze materialisatie te gebruiken. Of laat alles zoals het is, maar het zal op zijn minst ineffectief zijn als er bepaalde reeds vooraf berekende gegevens zijn, maar veel zoekopdrachten gebruiken deze niet altijd, maar herberekenen deze.

Ten tweede hebben ze een groot aantal beperkingen:

Oracle

5.3.8.4 Algemene beperkingen op snel vernieuwen

De bepalende vraag van de gerealiseerde weergave is als volgt beperkt:

  • De gematerialiseerde weergave mag geen verwijzingen bevatten naar niet-herhalende uitdrukkingen zoals SYSDATE en ROWNUM.
  • De gematerialiseerde weergave mag geen verwijzingen bevatten naar RAW or LONG RAW gegevenstypen.
  • Het kan geen a bevatten SELECT subquery weergeven.
  • Het kan geen analytische functies bevatten (bijvoorbeeld RANK) in de SELECT clausule.
  • Er kan niet worden verwezen naar een tabel waarop een XMLIndex index is gedefinieerd.
  • Het kan geen a bevatten MODEL clausule.
  • Het kan geen a bevatten HAVING clausule met een subquery.
  • Het mag geen geneste query's bevatten die dat wel hebben ANY, ALLof NOT EXISTS.
  • Het kan geen a bevatten [START WITH …] CONNECT BY clausule.
  • Het kan niet meerdere detailtabellen op verschillende locaties bevatten.
  • ON COMMIT Gematerialiseerde weergaven kunnen geen externe detailtabellen bevatten.
  • Geneste gerealiseerde weergaven moeten een join of aggregatie hebben.
  • Gematerialiseerde samengevoegde weergaven en gematerialiseerde samengestelde weergaven met een GROUP BY -clausule kan niet selecteren uit een indexgeorganiseerde tabel.

5.3.8.5 Beperkingen op snel vernieuwen van gerealiseerde weergaven met alleen joins

Voor het definiëren van query's voor gerealiseerde weergaven met alleen joins en zonder aggregaties gelden de volgende beperkingen voor snel vernieuwen:

  • Alle beperkingen van «Algemene beperkingen voor snel vernieuwen".
  • Dat kunnen ze niet hebben GROUP BY clausules of aggregaten.
  • Rowids van alle tabellen in de FROM lijst moet verschijnen in de SELECT lijst met de vraag.
  • Gematerialiseerde weergavelogboeken moeten bestaan ​​met rowids voor alle basistabellen in de FROM lijst met de vraag.
  • U kunt geen snel vernieuwbare, gerealiseerde weergave maken van meerdere tabellen met eenvoudige joins die een objecttypekolom in de tabel bevatten SELECT verklaring.

Bovendien zal de vernieuwingsmethode die u kiest niet optimaal efficiënt zijn als:

  • De definiërende query maakt gebruik van een outside join die zich gedraagt ​​als een inner join. Als de definiërende query een dergelijke join bevat, kunt u overwegen de definiërende query te herschrijven zodat deze een inner join bevat.
  • De SELECT lijst van de gerealiseerde weergave bevat uitdrukkingen voor kolommen uit meerdere tabellen.

5.3.8.6 Beperkingen op snel vernieuwen van gematerialiseerde weergaven met aggregaten

Voor het definiëren van query's voor gerealiseerde weergaven met aggregaties of joins gelden de volgende beperkingen voor snel vernieuwen:

Voor beide wordt snel vernieuwen ondersteund ON COMMIT en ON DEMAND gematerialiseerde opvattingen, maar de volgende beperkingen zijn van toepassing:

  • Alle tabellen in de gerealiseerde weergave moeten opgebouwde weergavelogboeken hebben, en de gerealiseerde weergavelogboeken moeten:
    • Bevat alle kolommen uit de tabel waarnaar wordt verwezen in de gerealiseerde weergave.
    • Specificeer met ROWID en INCLUDING NEW VALUES.
    • Geef het SEQUENCE -clausule als wordt verwacht dat de tabel een combinatie van invoegingen/direct-loads, verwijderingen en updates bevat.

  • Alleen SUM, COUNT, AVG, STDDEV, VARIANCE, MIN en MAX worden ondersteund voor snel vernieuwen.
  • COUNT(*) moet worden opgegeven.
  • Geaggregeerde functies mogen alleen voorkomen als het buitenste deel van de expressie. Dat wil zeggen, aggregaten zoals AVG(AVG(x)) or AVG(x)+ AVG(x) zijn niet toegestaan.
  • Voor elk aggregaat zoals AVG(expr), het overeenkomstige COUNT(expr) moet aanwezig zijn. Oracle raadt dat aan SUM(expr) wees duidelijk.
  • If VARIANCE(expr) or STDDEV(expr) is gespecificeerd, COUNT(expr) en SUM(expr) moet worden gespecificeerd. Oracle raadt dat aan SUM(expr *expr) wees duidelijk.
  • De SELECT kolom in de definiërende query kan geen complexe expressie zijn met kolommen uit meerdere basistabellen. Een mogelijke oplossing hiervoor is het gebruik van een geneste gematerialiseerde weergave.
  • De SELECT lijst moet alles bevatten GROUP BY kolommen.
  • De gerealiseerde weergave is niet gebaseerd op een of meer externe tabellen.
  • Als u een gebruikt CHAR gegevenstype in de filterkolommen van een gerealiseerde weergavelogboek, moeten de tekensets van de hoofdsite en de gerealiseerde weergave hetzelfde zijn.
  • Als de gerealiseerde weergave een van de volgende kenmerken heeft, wordt snel vernieuwen alleen ondersteund bij conventionele DML-invoegingen en directe ladingen.
    • Gematerialiseerde weergaven met MIN or MAX aggregaten
    • Gematerialiseerde opvattingen die dat wel hebben SUM(expr) maar nee COUNT(expr)
    • Gematerialiseerde weergaven zonder COUNT(*)

    Een dergelijke gematerialiseerde weergave wordt een gematerialiseerde weergave met uitsluitend invoegen genoemd.

  • Een gematerialiseerde visie met MAX or MIN is snel vernieuwbaar na verwijdering of gemengde DML-instructies als het geen WHERE clausule.
    De maximale/min snelle vernieuwing na verwijdering of gemengde DML gedraagt ​​zich niet hetzelfde als het geval van alleen invoegen. Het verwijdert en herberekent de max/min-waarden voor de betrokken groepen. U moet zich bewust zijn van de impact op de prestaties.
  • Gematerialiseerde weergaven met benoemde weergaven of subquery's in de FROM -clausule kan snel worden vernieuwd, op voorwaarde dat de weergaven volledig kunnen worden samengevoegd. Zie voor informatie over welke weergaven worden samengevoegd Oracle Database SQL-taalreferentie.
  • Als er geen outside joins zijn, zijn er mogelijk willekeurige selecties en joins in de WHERE clausule.
  • Gematerialiseerde aggregatieweergaven met buitenste joins kunnen snel worden vernieuwd na conventionele DML en directe belastingen, op voorwaarde dat alleen de buitenste tabel is gewijzigd. Er moeten ook unieke beperkingen bestaan ​​voor de join-kolommen van de binnenste join-tabel. Als er buitenste joins zijn, moeten alle joins met elkaar worden verbonden ANDs en moet de gelijkheid gebruiken (=) exploitant.
  • Voor gematerialiseerde weergaven met CUBE, ROLLUP, groeperingssets of aaneenschakeling daarvan, gelden de volgende beperkingen:
    • De SELECT lijst moet een groeperingsonderscheider bevatten die een GROUPING_ID functie op allemaal GROUP BY uitdrukkingen of GROUPING functioneert één voor elk GROUP BY uitdrukking. Als bijvoorbeeld de GROUP BY clausule van de gematerialiseerde visie is "GROUP BY CUBE(a, b)", dan de SELECT lijst moet een van beide bevatten "GROUPING_ID(a, b)»Of«GROUPING(a) AND GROUPING(b)» zodat de gematerialiseerde weergave snel kan worden vernieuwd.
    • GROUP BY mag niet resulteren in dubbele groeperingen. Bijvoorbeeld, "GROUP BY a, ROLLUP(a, b)" kan niet snel worden vernieuwd omdat dit resulteert in dubbele groeperingen "(a), (a, b), AND (a)".

5.3.8.7 Beperkingen op snel vernieuwen van gematerialiseerde weergaven met UNION ALL

Gematerialiseerde weergaven met de UNION ALL set operator ondersteunt de REFRESH FAST optie als aan de volgende voorwaarden is voldaan:

  • De definiërende query moet de UNION ALL operator op topniveau.

    De UNION ALL operator kan niet worden ingebed in een subquery, met één uitzondering: de UNION ALL kan in een subquery in de FROM -clausule, op voorwaarde dat de definiërende query de vorm heeft SELECT * FROM (bekijken of subquery met UNION ALL) zoals in het volgende voorbeeld:

    CREËER WEERGAVE view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM klanten c WAAR c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM klanten c WHERE c.cust_last_name = 'Jones'); CREËER GEMATERIALISEERDE BEKIJK unionall_inside_view_mv VERNIEUW SNEL OP AANVRAAG ALS SELECTEER * UIT view_with_unionall;
    

    Merk op dat het uitzicht view_with_unionall voldoet aan de vereisten voor snelle verversing.

  • Elk queryblok in het UNION ALL query moet voldoen aan de vereisten van een snel vernieuwbare gematerialiseerde weergave met aggregaten of een snel vernieuwbare gematerialiseerde weergave met joins.

    De juiste gematerialiseerde weergavelogboeken moeten voor de tabellen worden aangemaakt, zoals vereist voor het corresponderende type snel vernieuwbare gematerialiseerde weergave.
    Merk op dat de Oracle Database ook het speciale geval toestaat van een gematerialiseerde weergave van een enkele tabel met uitsluitend joins, op voorwaarde dat de ROWID kolom is opgenomen in de SELECT lijst en in het gerealiseerde weergavelogboek. Dit wordt weergegeven in de definiërende query van de weergave view_with_unionall.

  • De SELECT lijst van elke zoekopdracht moet een UNION ALL markering, en de UNION ALL kolom moet in elke kolom een ​​afzonderlijke constante numerieke waarde of tekenreekswaarde hebben UNION ALL tak. Verder moet de markeringskolom op dezelfde ordinale positie verschijnen in de SELECT lijst van elk queryblok. Zien "UNION ALL Marker en query herschrijven» voor meer informatie over UNION ALL markers.
  • Sommige functies, zoals outside joins, alleen ingevoegde geaggregeerde weergavequery's en externe tabellen, worden niet ondersteund voor gerealiseerde weergaven met UNION ALL. Houd er echter rekening mee dat gerealiseerde weergaven die bij replicatie worden gebruikt en die geen joins of aggregaties bevatten, snel kunnen worden vernieuwd wanneer UNION ALL of externe tabellen worden gebruikt.
  • De compatibiliteitsinitialisatieparameter moet worden ingesteld op 9.2.0 of hoger om een ​​snel vernieuwbare gematerialiseerde weergave te kunnen maken UNION ALL.

Ik wil Oracle-fans niet beledigen, maar afgaande op hun lijst met beperkingen lijkt het erop dat dit mechanisme niet in het algemeen is geschreven, met behulp van een bepaald model, maar door duizenden Indiërs, waarbij iedereen de kans kreeg om schreven hun eigen tak, en elk van hen deed wat hij kon. Het gebruik van dit mechanisme voor echte logica is alsof je door een mijnenveld loopt. Je kunt op elk moment een mijn krijgen door op een van de niet voor de hand liggende beperkingen te klikken. Hoe het werkt is ook een aparte vraag, maar valt buiten het bestek van dit artikel.

Microsoft SQL Server

Aanvullende vereisten

Naast de SET-opties en deterministische functie-eisen moet aan de volgende eisen worden voldaan:

  • De gebruiker die uitvoert CREATE INDEX moet de eigenaar van de weergave zijn.
  • Wanneer u de index maakt, wordt de IGNORE_DUP_KEY optie moet zijn ingesteld op UIT (de standaardinstelling).
  • Naar tabellen moet worden verwezen met tweedelige namen, schema.tafel naam in de weergavedefinitie.
  • Door de gebruiker gedefinieerde functies waarnaar in de weergave wordt verwezen, moeten worden gemaakt met behulp van de WITH SCHEMABINDING optie.
  • Naar alle door de gebruiker gedefinieerde functies waarnaar in de weergave wordt verwezen, moet worden verwezen met tweedelige namen, ..
  • De eigenschap voor gegevenstoegang van een door de gebruiker gedefinieerde functie moet zijn NO SQL, en de eigenschap externe toegang moet zijn NO.
  • CLR-functies (Common Language Runtime) kunnen worden weergegeven in de selectielijst van de weergave, maar kunnen geen deel uitmaken van de definitie van de geclusterde indexsleutel. CLR-functies kunnen niet voorkomen in de WHERE-clausule van de weergave of de ON-clausule van een JOIN-bewerking in de weergave.
  • Voor CLR-functies en -methoden van door de gebruiker gedefinieerde CLR-typen die in de weergavedefinitie worden gebruikt, moeten de eigenschappen zijn ingesteld zoals weergegeven in de volgende tabel.

    Woning
    Note

    DETERMINISTISCH = WAAR
    Moet expliciet worden gedeclareerd als attribuut van de Microsoft .NET Framework-methode.

    PRECIES = WAAR
    Moet expliciet worden gedeclareerd als attribuut van de .NET Framework-methode.

    GEGEVENSTOEGANG = GEEN SQL
    Bepaald door het DataAccess-attribuut in te stellen op DataAccessKind.None en het SystemDataAccess-attribuut op SystemDataAccessKind.None.

    EXTERNE TOEGANG = NEE
    Deze eigenschap is standaard ingesteld op NO voor CLR-routines.

  • De weergave moet worden gemaakt met behulp van de WITH SCHEMABINDING optie.
  • De weergave mag alleen verwijzen naar basistabellen die zich in dezelfde database bevinden als de weergave. De weergave kan niet verwijzen naar andere weergaven.
  • De SELECT-instructie in de weergavedefinitie mag de volgende Transact-SQL-elementen niet bevatten:

    COUNT
    ROWSET-functies (OPENDATASOURCE, OPENQUERY, OPENROWSETEN OPENXML)
    OUTER doet mee(LEFT, RIGHTof FULL)

    Afgeleide tabel (gedefinieerd door het opgeven van een SELECT verklaring in de FROM clausule)
    Zelf-voegt
    Kolommen opgeven met behulp van SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARPof AVG
    Algemene tabelexpressie (CTE)

    drijven1, tekst, ntekst, beeld, XMLof Bestandsstroom kolommen
    Subquery
    OVER clausule, die rangschikkings- of aggregatievensterfuncties bevat

    Predikaten in de volledige tekst (CONTAINS, FREETEXT)
    SUM functie die verwijst naar een null-expressie
    ORDER BY

    Door de gebruiker gedefinieerde aggregatiefunctie van CLR
    TOP
    CUBE, ROLLUPof GROUPING SETS exploitanten

    MIN, MAX
    UNION, EXCEPTof INTERSECT exploitanten
    TABLESAMPLE

    Tabelvariabelen
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Schaarse kolommensets
    Inline (TVF) of multi-statement tabelwaardefuncties (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 De geïndexeerde weergave kan bevatten drijven kolommen; Dergelijke kolommen kunnen echter niet worden opgenomen in de geclusterde indexsleutel.

  • If GROUP BY aanwezig is, moet de VIEW-definitie bevatten COUNT_BIG(*) en mag niet bevatten HAVING. Deze GROUP BY beperkingen zijn alleen van toepassing op de geïndexeerde weergavedefinitie. Een query kan een geïndexeerde weergave gebruiken in het uitvoeringsplan, zelfs als deze hier niet aan voldoet GROUP BY beperkingen.
  • Als de weergavedefinitie een GROUP BY -clausule kan de sleutel van de unieke geclusterde index alleen verwijzen naar de kolommen die zijn opgegeven in de GROUP BY clausule.

Het is hier duidelijk dat de Indiërs er niet bij betrokken waren, aangezien ze besloten het te doen volgens het schema ‘we zullen weinig, maar goed doen’. Dat wil zeggen, ze hebben meer mijnen op het veld, maar hun locatie is transparanter. Het meest teleurstellende is deze beperking:

De weergave mag alleen verwijzen naar basistabellen die zich in dezelfde database bevinden als de weergave. De weergave kan niet verwijzen naar andere weergaven.

In onze terminologie betekent dit dat een functie geen toegang heeft tot een andere gematerialiseerde functie. Daarmee wordt alle ideologie in de kiem gesmoord.
Ook vermindert deze beperking (en verder in de tekst) de gebruiksscenario's aanzienlijk:

De SELECT-instructie in de weergavedefinitie mag de volgende Transact-SQL-elementen niet bevatten:

COUNT
ROWSET-functies (OPENDATASOURCE, OPENQUERY, OPENROWSETEN OPENXML)
OUTER doet mee(LEFT, RIGHTof FULL)

Afgeleide tabel (gedefinieerd door het opgeven van een SELECT verklaring in de FROM clausule)
Zelf-voegt
Kolommen opgeven met behulp van SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARPof AVG
Algemene tabelexpressie (CTE)

drijven1, tekst, ntekst, beeld, XMLof Bestandsstroom kolommen
Subquery
OVER clausule, die rangschikkings- of aggregatievensterfuncties bevat

Predikaten in de volledige tekst (CONTAINS, FREETEXT)
SUM functie die verwijst naar een null-expressie
ORDER BY

Door de gebruiker gedefinieerde aggregatiefunctie van CLR
TOP
CUBE, ROLLUPof GROUPING SETS exploitanten

MIN, MAX
UNION, EXCEPTof INTERSECT exploitanten
TABLESAMPLE

Tabelvariabelen
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Schaarse kolommensets
Inline (TVF) of multi-statement tabelwaardefuncties (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY en andere zijn verboden. Het was misschien gemakkelijker geweest om te specificeren wat wel kon worden gebruikt, dan wat niet kon worden gebruikt. De lijst zou waarschijnlijk veel kleiner zijn.

Samenvattend: een enorme reeks beperkingen in elk (laten we er rekening mee houden commerciële) DBMS versus geen enkele (met uitzondering van één logische, niet technische) in LGPL-technologie. Er moet echter worden opgemerkt dat het implementeren van dit mechanisme in relationele logica iets moeilijker is dan in de beschreven functionele logica.

uitvoering

Hoe het werkt? PostgreSQL wordt gebruikt als een “virtuele machine”. Er zit een complex algoritme in dat queries bouwt. Hier bron. En er is niet alleen een grote reeks heuristieken met een heleboel ifs. Dus als je een paar maanden hebt om te studeren, kun je proberen architectuur te begrijpen.

Werkt het effectief? Heel effectief. Helaas is dit lastig te bewijzen. Ik kan alleen maar zeggen dat als je de duizenden queries in grote applicaties in ogenschouw neemt, deze gemiddeld efficiënter zijn dan die van een goede ontwikkelaar. Een uitstekende SQL-programmeur kan elke vraag efficiënter schrijven, maar met duizend vragen heeft hij eenvoudigweg niet de motivatie of de tijd om het te doen. Het enige dat ik nu kan aanhalen als bewijs van de effectiviteit is dat er verschillende projecten werken aan het platform dat op dit DBMS is gebouwd ERP-systemen, die duizenden verschillende GEMATERIALISEERDE functies hebben, met duizenden gebruikers en terabyte-databases met honderden miljoenen records die op een gewone server met twee processors draaien. Iedereen kan de effectiviteit echter controleren/weerleggen door te downloaden het platform en PostgreSQL, Opgewonden SQL-query's registreren en proberen de logica en gegevens daar te wijzigen.

In de volgende artikelen zal ik het ook hebben over hoe je beperkingen kunt instellen op functies, kunt werken met wijzigingssessies en nog veel meer.

Bron: www.habr.com

Voeg een reactie