Balansera skriver och läser i en databas

Balansera skriver och läser i en databas
I det föregående artikeln Jag beskrev konceptet och implementeringen av en databas byggd på funktioner, snarare än tabeller och fält som i relationsdatabaser. Den gav många exempel som visade fördelarna med detta tillvägagångssätt jämfört med det klassiska. Många tyckte att de inte var tillräckligt övertygande.

I den här artikeln kommer jag att visa hur detta koncept gör att du snabbt och bekvämt kan balansera skrivningar och läsningar till databasen utan någon förändring i driftslogiken. Liknande funktionalitet har försökt implementeras i moderna kommersiella DBMS:er (särskilt Oracle och Microsoft SQL Server). I slutet av artikeln ska jag visa att det de gjorde, milt uttryckt, inte fungerade särskilt bra.

beskrivning

Som tidigare, för bättre förståelse kommer jag att börja beskrivningen med exempel. Låt oss säga att vi behöver implementera logik som kommer att returnera en lista över avdelningar med antalet anställda i dem och deras totala lön.

I en funktionell databas skulle det se ut så här:

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

Komplexiteten i att köra denna fråga i alla DBMS kommer att motsvara O(antal anställda)eftersom denna beräkning kräver att man skannar hela tabellen över anställda och sedan grupperar dem efter avdelning. Det kommer också att finnas några små (vi tror att det är många fler anställda än avdelningar) tillägg beroende på vald plan O(logg antal anställda) eller O(antal avdelningar) för gruppering och så vidare.

Det är tydligt att exekveringsoverheaden kan vara olika i olika DBMS, men komplexiteten kommer inte att förändras på något sätt.

I den föreslagna implementeringen kommer den funktionella DBMS att generera en underfråga som kommer att beräkna de erforderliga värdena för avdelningen och sedan göra en JOIN med avdelningstabellen för att få namnet. Men för varje funktion, vid deklarering, är det möjligt att ställa in en speciell MATERIALISERAD markör. Systemet kommer automatiskt att skapa ett motsvarande fält för varje sådan funktion. När du ändrar värdet på en funktion kommer värdet på fältet också att ändras i samma transaktion. När du använder den här funktionen kommer det förberäknade fältet att nås.

I synnerhet om du ställer in MATERIALISERAD för funktioner räkna anställda и lönSumma, då kommer två fält att läggas till i tabellen med listan över avdelningar, som lagrar antalet anställda och deras totala lön. Närhelst det sker en förändring av anställda, deras löner eller avdelningstillhörighet kommer systemet automatiskt att ändra värdena för dessa fält. Ovanstående fråga kommer direkt åt dessa fält och kommer att köras i O(antal avdelningar).

Vilka är begränsningarna? Bara en sak: en sådan funktion måste ha ett ändligt antal ingångsvärden för vilka dess värde är definierat. Annars kommer det att vara omöjligt att bygga en tabell som lagrar alla dess värden, eftersom det inte kan finnas en tabell med ett oändligt antal rader.

Exempel:

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

Denna funktion är definierad för ett oändligt antal värden på N (till exempel är vilket negativt värde som helst lämpligt). Därför kan du inte lägga MATERIALIZED på den. Så detta är en logisk begränsning, inte en teknisk (det vill säga inte för att vi inte kunde implementera den). Annars finns det inga begränsningar. Du kan använda grupperingar, sortering, OCH och ELLER, PARTITION, rekursion, etc.

Till exempel, i problem 2.2 i föregående artikel, kan du lägga MATERIALIZED på båda funktionerna:

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 i sig kommer att skapa en tabell med typnycklar Kund, Produkt и HELTAL, kommer att lägga till två fält till den och kommer att uppdatera fältvärdena i dem med eventuella ändringar. När ytterligare anrop till dessa funktioner görs kommer de inte att beräknas, utan snarare läses värdena från motsvarande fält.

Med denna mekanism kan du till exempel bli av med rekursioner (CTE) i frågor. Tänk särskilt på grupper som bildar ett träd med hjälp av relationen barn/förälder (varje grupp har en länk till sin förälder):

parent = DATA Group (Group);

I en funktionell databas kan rekursionslogik specificeras enligt följande:

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;

Sedan för funktionen är Förälder är märkt MATERIALISERAD, då skapas en tabell med två nycklar (grupper) för den, där fältet är Förälder kommer att vara sant endast om den första nyckeln är ett barn till den andra. Antalet poster i denna tabell kommer att vara lika med antalet grupper multiplicerat med trädets genomsnittliga djup. Om du till exempel behöver räkna antalet ättlingar till en viss grupp kan du använda den här funktionen:

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

Det kommer inte att finnas någon CTE i SQL-frågan. Istället blir det en enkel GROUP BY.

Med den här mekanismen kan du också enkelt avnormalisera databasen om det behövs:

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

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

När du anropar en funktion datum för orderraden kommer fältet för vilket det finns ett index att läsas från tabellen med orderrader. När orderdatumet ändras kommer systemet självt automatiskt att räkna om det denormaliserade datumet i raden.

Fördelar

Vad är hela denna mekanism till för? I klassiska DBMS:er, utan att skriva om frågor, kan en utvecklare eller DBA bara ändra index, fastställa statistik och tala om för frågeplaneraren hur de ska köras (och TIPS är endast tillgängliga i kommersiella DBMS). Oavsett hur mycket de försöker, kommer de inte att kunna slutföra den första frågan i artikeln i O (antal avdelningar) utan att ändra frågor eller lägga till triggers. I det föreslagna schemat behöver du i utvecklingsstadiet inte tänka på datalagringsstrukturen och vilka aggregationer som ska användas. Allt detta kan enkelt ändras i farten, direkt i drift.

I praktiken ser det ut så här. Vissa människor utvecklar logik direkt utifrån uppgiften. De förstår inte algoritmer och deras komplexitet, inte heller genomförandeplaner, inte heller typer av kopplingar eller någon annan teknisk komponent. Dessa människor är mer affärsanalytiker än utvecklare. Sedan går allt detta till testning eller drift. Möjliggör loggning av långvariga frågor. När en lång fråga upptäcks, beslutar andra personer (mer tekniska - i huvudsak DBA) att aktivera MATERIALIZED på någon mellanfunktion. Detta saktar ner inspelningen lite (eftersom det kräver uppdatering av ytterligare ett fält i transaktionen). Men inte bara denna fråga snabbas upp betydligt, utan även alla andra som använder den här funktionen. Samtidigt är det relativt enkelt att bestämma vilken funktion som ska realiseras. Två huvudparametrar: antalet möjliga ingångsvärden (detta är hur många poster som kommer att finnas i motsvarande tabell) och hur ofta det används i andra funktioner.

analoger

Moderna kommersiella DBMS:er har liknande mekanismer: MATERIALISERAD VISNING med FAST REFRESH (Oracle) och INDEXED VIEW (Microsoft SQL Server). I PostgreSQL kan MATERIALIZED VIEW inte uppdateras i en transaktion, utan endast på begäran (och även med mycket strikta begränsningar), så vi överväger det inte. Men de har flera problem som avsevärt begränsar deras användning.

För det första kan du bara aktivera materialisering om du redan har skapat en vanlig VIEW. Annars måste du skriva om de återstående förfrågningarna för att komma åt den nyskapade vyn för att använda denna materialisering. Eller lämna allt som det är, men det kommer att vara åtminstone ineffektivt om det finns vissa redan förberäknade data, men många frågor använder det inte alltid, utan räknar om det.

För det andra har de ett stort antal begränsningar:

Oracle

5.3.8.4 Allmänna begränsningar för snabbuppdatering

Den definierande frågan för den materialiserade vyn är begränsad enligt följande:

  • Den materialiserade vyn får inte innehålla referenser till icke-repeterande uttryck som SYSDATE och ROWNUM.
  • Den materialiserade vyn får inte innehålla referenser till RAW or LONG RAW datatyper.
  • Den kan inte innehålla en SELECT lista underfråga.
  • Den kan inte innehålla analytiska funktioner (t.ex. RANK) I SELECT klausul.
  • Den kan inte referera till en tabell där en XMLIndex index definieras.
  • Den kan inte innehålla en MODEL klausul.
  • Den kan inte innehålla en HAVING klausul med en underfråga.
  • Den kan inte innehålla kapslade frågor som har ANY, ALL, eller NOT EXISTS.
  • Den kan inte innehålla en [START WITH …] CONNECT BY klausul.
  • Den kan inte innehålla flera detaljtabeller på olika platser.
  • ON COMMIT materialiserade vyer kan inte ha avlägsna detaljtabeller.
  • Kapslade materialiserade vyer måste ha en sammanfogning eller sammanställning.
  • Materialiserade sammanfogningsvyer och materialiserade aggregerade vyer med en GROUP BY sats kan inte väljas från en indexorganiserad tabell.

5.3.8.5 Restriktioner för snabb uppdatering av materialiserade vyer med endast anslutningar

Att definiera frågor för materialiserade vyer med endast kopplingar och inga aggregat har följande begränsningar för snabbuppdatering:

  • Alla restriktioner från «Allmänna begränsningar för snabbuppdatering".
  • De kan inte ha GROUP BY klausuler eller aggregat.
  • Rowids av alla tabeller i FROM listan måste visas i SELECT listan över frågan.
  • Materialiserade vyloggar måste finnas med radider för alla bastabeller i FROM listan över frågan.
  • Du kan inte skapa en snabb uppdateringsbar materialiserad vy från flera tabeller med enkla kopplingar som inkluderar en objekttypskolumn i SELECT uttalande.

Dessutom kommer uppdateringsmetoden du väljer inte att vara optimalt effektiv om:

  • Den definierande frågan använder en yttre koppling som beter sig som en inre koppling. Om den definierande frågan innehåller en sådan koppling, överväg att skriva om den definierande frågan så att den innehåller en inre koppling.
  • Smakämnen SELECT listan över den materialiserade vyn innehåller uttryck på kolumner från flera tabeller.

5.3.8.6 Restriktioner för snabb uppdatering av materialiserade vyer med aggregat

Att definiera frågor för materialiserade vyer med aggregat eller kopplingar har följande begränsningar för snabbuppdatering:

Snabbuppdatering stöds för båda ON COMMIT och ON DEMAND materialiserade vyer, men följande begränsningar gäller:

  • Alla tabeller i den materialiserade vyn måste ha materialiserade vyloggar, och de materialiserade vyloggarna måste:
    • Innehåller alla kolumner från tabellen som refereras till i den materialiserade vyn.
    • Ange med ROWID och INCLUDING NEW VALUES.
    • ange SEQUENCE om tabellen förväntas ha en blandning av infogningar/direktladdningar, borttagningar och uppdateringar.

  • Endast SUM, COUNT, AVG, STDDEV, VARIANCE, MIN och MAX stöds för snabb uppdatering.
  • COUNT(*) måste anges.
  • Aggregerade funktioner får endast förekomma som den yttersta delen av uttrycket. Det vill säga aggregat som t.ex AVG(AVG(x)) or AVG(x)+ AVG(x) är inte tillåten.
  • För varje aggregat som t.ex AVG(expr), korresponderande COUNT(expr) måste vara närvarande. Oracle rekommenderar det SUM(expr) specificeras.
  • If VARIANCE(expr) or STDDEV(expr) är specificerad, COUNT(expr) och SUM(expr) måste anges. Oracle rekommenderar det SUM(expr *expr) specificeras.
  • Smakämnen SELECT kolumnen i den definierande frågan kan inte vara ett komplext uttryck med kolumner från flera bastabeller. En möjlig lösning på detta är att använda en kapslad materialiserad vy.
  • Smakämnen SELECT listan måste innehålla alla GROUP BY kolumner.
  • Den materialiserade vyn är inte baserad på en eller flera fjärrtabeller.
  • Om du använder en CHAR datatyp i filterkolumnerna i en materialiserad vylogg måste teckenuppsättningarna för huvudwebbplatsen och den materialiserade vyn vara desamma.
  • Om den materialiserade vyn har något av följande stöds snabb uppdatering endast på konventionella DML-inlägg och direktladdningar.
    • Materialiserade vyer med MIN or MAX aggregat
    • Materialiserade synpunkter som har SUM(expr) men nej COUNT(expr)
    • Materialiserade vyer utan COUNT(*)

    En sådan materialiserad vy kallas en materialiserad vy som endast kan infogas.

  • En materialiserad vy med MAX or MIN är snabbt uppdateringsbar efter borttagning eller blandade DML-satser om den inte har en WHERE klausul.
    Snabbuppdateringen för max/min efter radering eller blandad DML har inte samma beteende som fallet med enbart infogning. Den tar bort och beräknar om max/min-värdena för de berörda grupperna. Du måste vara medveten om dess prestandapåverkan.
  • Materialiserade vyer med namngivna vyer eller underfrågor i FROM klausulen kan snabbt uppdateras förutsatt att vyerna kan slås samman helt. För information om vilka vyer som kommer att slås samman, se Oracle Database SQL Language Reference.
  • Om det inte finns några yttre kopplingar kan du ha godtyckliga val och kopplingar i WHERE klausul.
  • Materialiserade samlade vyer med yttre sammanfogningar är snabbt uppdateringsbara efter konventionell DML och direkt belastning, förutsatt att endast den yttre tabellen har modifierats. Det måste också finnas unika begränsningar på kopplingskolumnerna i den inre kopplingstabellen. Om det finns yttre skarvar måste alla skarvar anslutas med ANDs och måste använda jämställdheten (=) operatör.
  • För materialiserade vyer med CUBE, ROLLUP, grupperingsuppsättningar eller sammanlänkning av dem, gäller följande begränsningar:
    • Smakämnen SELECT listan bör innehålla en grupperingssärskiljare som antingen kan vara en GROUPING_ID funktion på alla GROUP BY uttryck eller GROUPING funktioner en för varje GROUP BY uttryck. Till exempel, om GROUP BY klausulen i den materialiserade uppfattningen är "GROUP BY CUBE(a, b)", sedan SELECT listan bör innehålla antingen "GROUPING_ID(a, b)» eller «GROUPING(a) AND GROUPING(b)» för att den materialiserade vyn snabbt ska kunna uppdateras.
    • GROUP BY bör inte resultera i några dubbla grupperingar. Till exempel, "GROUP BY a, ROLLUP(a, b)" går inte att uppdatera snabbt eftersom det resulterar i dubbla grupperingar "(a), (a, b), AND (a)".

5.3.8.7 Restriktioner för snabb uppdatering av materialiserade vyer med UNION ALL

Materialiserade vyer med UNION ALL ställ in operatörsstöd REFRESH FAST alternativ om följande villkor är uppfyllda:

  • Den definierande frågan måste ha UNION ALL operatör på toppnivå.

    Smakämnen UNION ALL operatorn kan inte bäddas in i en underfråga, med ett undantag: The UNION ALL kan vara i en underfråga i FROM klausul förutsatt att den definierande frågan är av formen SELECT * FROM (visa eller underfråga med UNION ALL) som i följande exempel:

    CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM customers 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'); SKAPA MATERIALISERAD VY unionall_inside_view_mv UPPDATERA SNABB PÅ DEMAND SOM VALT * FRÅN view_with_unionall;
    

    Observera att vyn view_with_unionall uppfyller kraven för snabb uppdatering.

  • Varje frågeblock i UNION ALL frågan måste uppfylla kraven för en snabb uppdateringsbar materialiserad vy med aggregat eller en snabb uppdateringsbar materialiserad vy med kopplingar.

    Lämpliga materialiserade vyloggar måste skapas på tabellerna efter behov för motsvarande typ av snabb uppdateringsbar materialiserad vy.
    Observera att Oracle-databasen också tillåter det speciella fallet med en enda tabellmaterialiserad vy med joins endast förutsatt att ROWID kolumnen har inkluderats i SELECT listan och i den materialiserade vyloggen. Detta visas i vyns definierande fråga view_with_unionall.

  • Smakämnen SELECT listan över varje fråga måste innehålla en UNION ALL markör och UNION ALL kolumn måste ha ett distinkt konstant numeriskt eller strängvärde i varje UNION ALL gren. Vidare måste markörkolumnen visas i samma ordningsposition i SELECT lista över varje frågeblock. Ser "UNION ALL Markör och fråga omskrivning» för mer information ang UNION ALL markörer.
  • Vissa funktioner som yttre kopplingar, infogade aggregerade materialiserade vyfrågor och fjärrtabeller stöds inte för materialiserade vyer med UNION ALL. Observera dock att materialiserade vyer som används i replikering, som inte innehåller kopplingar eller aggregat, snabbt kan uppdateras när UNION ALL eller fjärrbord används.
  • Kompatibilitetsinitieringsparametern måste ställas in på 9.2.0 eller högre för att skapa en snabb uppdateringsbar materialiserad vy med UNION ALL.

Jag vill inte förolämpa Oracle-fans, men att döma av deras lista över begränsningar verkar det som att denna mekanism inte skrevs i det allmänna fallet, med någon form av modell, utan av tusentals indier, där alla fick möjlighet att skriv sin egen gren, och var och en av dem gjorde vad han kunde och gjorde. Att använda denna mekanism för riktig logik är som att gå genom ett minfält. Du kan få en min när som helst genom att träffa en av de icke-uppenbara restriktionerna. Hur det fungerar är också en separat fråga, men det ligger utanför ramen för denna artikel.

Microsoft SQL Server

Ytterligare krav

Utöver SET-alternativen och deterministiska funktionskraven måste följande krav uppfyllas:

  • Användaren som kör CREATE INDEX måste vara ägare till vyn.
  • När du skapar indexet visas IGNORE_DUP_KEY alternativet måste vara inställt på AV (standardinställningen).
  • Tabeller måste refereras med tvådelade namn, schema.tabellnamn i vydefinitionen.
  • Användardefinierade funktioner som refereras till i vyn måste skapas med hjälp av WITH SCHEMABINDING alternativ.
  • Alla användardefinierade funktioner som refereras till i vyn måste refereras med tvådelade namn, ..
  • Dataåtkomstegenskapen för en användardefinierad funktion måste vara NO SQL, och extern åtkomst egendom måste vara NO.
  • Common Language Runtime (CLR)-funktioner kan visas i vyns vallista, men kan inte vara en del av definitionen av den klustrade indexnyckeln. CLR-funktioner kan inte visas i WHERE-satsen i vyn eller ON-satsen för en JOIN-operation i vyn.
  • CLR-funktioner och -metoder för CLR-användardefinierade typer som används i vydefinitionen måste ha de egenskaper som anges i följande tabell.

    Fast egendom
    Anmärkningar

    DETERMINISTISK = SANT
    Måste uttryckligen deklareras som ett attribut för Microsoft .NET Framework-metoden.

    PRECIS = SANT
    Måste uttryckligen deklareras som ett attribut för .NET Framework-metoden.

    DATAÅTKOMST = INGEN SQL
    Bestäms genom att sätta DataAccess-attributet till DataAccessKind.None och SystemDataAccess-attributet till SystemDataAccessKind.None.

    EXTERN ÅTKOMST = NEJ
    Den här egenskapen är som standard NO för CLR-rutiner.

  • Vyn måste skapas med hjälp av WITH SCHEMABINDING alternativ.
  • Vyn måste endast referera till bastabeller som finns i samma databas som vyn. Vyn kan inte referera till andra vyer.
  • SELECT-satsen i vydefinitionen får inte innehålla följande Transact-SQL-element:

    COUNT
    ROWSET funktioner (OPENDATASOURCE, OPENQUERY, OPENROWSET, Och OPENXML)
    OUTER går med (LEFT, RIGHT, eller FULL)

    Härledd tabell (definieras genom att ange en SELECT uttalande i FROM klausul)
    Själv går med
    Ange kolumner med hjälp av SELECT * or SELECT <table_name>.*

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

    flyta1, text, ntext, bild, XML, eller filström kolonner
    Underfråga
    OVER klausul, som inkluderar rangordning eller aggregerade fönsterfunktioner

    Fulltextpredikat (CONTAINS, FREETEXT)
    SUM funktion som refererar till ett nullbart uttryck
    ORDER BY

    CLR användardefinierad aggregatfunktion
    TOP
    CUBE, ROLLUP, eller GROUPING SETS operatörer

    MIN, MAX
    UNION, EXCEPT, eller INTERSECT operatörer
    TABLESAMPLE

    Tabellvariabler
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Glesa kolumnuppsättningar
    Inline (TVF) eller multi-statement table-valued functions (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Den indexerade vyn kan innehålla flyta kolumner; sådana kolumner kan dock inte inkluderas i den klustrade indexnyckeln.

  • If GROUP BY finns, måste VIEW-definitionen innehålla COUNT_BIG(*) och får inte innehålla HAVING. Dessa GROUP BY begränsningar är endast tillämpliga på definitionen av den indexerade vyn. En fråga kan använda en indexerad vy i sin exekveringsplan även om den inte uppfyller dessa GROUP BY restriktioner.
  • Om vydefinitionen innehåller en GROUP BY sats, kan nyckeln till det unika klustrade indexet endast referera till de kolumner som anges i GROUP BY klausul.

Det är tydligt här att indianerna inte var inblandade, eftersom de bestämde sig för att göra det enligt schemat "vi kommer att göra lite, men bra." Det vill säga att de har fler gruvor på fältet, men deras placering är mer transparent. Det mest nedslående är denna begränsning:

Vyn måste endast referera till bastabeller som finns i samma databas som vyn. Vyn kan inte referera till andra vyer.

I vår terminologi betyder detta att en funktion inte kan komma åt en annan materialiserad funktion. Detta skär ner all ideologi i knoppen.
Dessutom minskar denna begränsning (och längre fram i texten) användningsfallen avsevärt:

SELECT-satsen i vydefinitionen får inte innehålla följande Transact-SQL-element:

COUNT
ROWSET funktioner (OPENDATASOURCE, OPENQUERY, OPENROWSET, Och OPENXML)
OUTER går med (LEFT, RIGHT, eller FULL)

Härledd tabell (definieras genom att ange en SELECT uttalande i FROM klausul)
Själv går med
Ange kolumner med hjälp av SELECT * or SELECT <table_name>.*

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

flyta1, text, ntext, bild, XML, eller filström kolonner
Underfråga
OVER klausul, som inkluderar rangordning eller aggregerade fönsterfunktioner

Fulltextpredikat (CONTAINS, FREETEXT)
SUM funktion som refererar till ett nullbart uttryck
ORDER BY

CLR användardefinierad aggregatfunktion
TOP
CUBE, ROLLUP, eller GROUPING SETS operatörer

MIN, MAX
UNION, EXCEPT, eller INTERSECT operatörer
TABLESAMPLE

Tabellvariabler
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Glesa kolumnuppsättningar
Inline (TVF) eller multi-statement table-valued functions (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY och andra är förbjudna. Det hade kanske varit lättare att specificera vad som kunde användas snarare än vad som inte kunde användas. Listan skulle förmodligen bli mycket kortare.

För att sammanfatta: en enorm uppsättning begränsningar i varje (låt oss notera kommersiella) DBMS vs ingen (med undantag av en logisk, inte teknisk) i LGPL-teknik. Det bör dock noteras att implementering av denna mekanism i relationslogik är något svårare än i den beskrivna funktionella logiken.

genomförande

Hur det fungerar? PostgreSQL används som en "virtuell maskin". Det finns en komplex algoritm inuti som bygger frågor. Här källkod. Och det finns inte bara en stor uppsättning heuristik med en massa om. Så om du har ett par månader på dig att studera kan du försöka förstå arkitektur.

Fungerar det effektivt? Ganska effektivt. Tyvärr är detta svårt att bevisa. Jag kan bara säga att om du tar hänsyn till de tusentals frågor som finns i stora applikationer, så är de i genomsnitt mer effektiva än en bra utvecklare. En utmärkt SQL-programmerare kan skriva vilken fråga som helst mer effektivt, men med tusen frågor har han helt enkelt inte motivationen eller tiden att göra det. Det enda jag nu kan citera som bevis på effektivitet är att flera projekt arbetar på plattformen byggd på detta DBMS ERP-system, som har tusentals olika MATERIALISERADE funktioner, med tusentals användare och terabytedatabaser med hundratals miljoner poster som körs på en vanlig server med två processorer. Däremot kan vem som helst kontrollera/motbevisa effektiviteten genom att ladda ner plattform och PostgreSQL, påslagen loggar SQL-frågor och försöker ändra logiken och data där.

I de följande artiklarna kommer jag också att prata om hur du kan sätta begränsningar på funktioner, arbeta med förändringssessioner och mycket mer.

Källa: will.com

Lägg en kommentar