Vyvážení zápisu a čtení v databázi

Vyvážení zápisu a čtení v databázi
V předchozím článku Popisoval jsem koncept a implementaci databáze založené na funkcích, nikoli na tabulkách a polích, jako v relačních databázích. Obsahovala mnoho příkladů, které ukazují výhody tohoto přístupu oproti klasickému. Mnozí je považovali za nedostatečně přesvědčivé.

V tomto článku ukážu, jak tento koncept umožňuje rychle a pohodlně vyvažovat zapisování a čtení do databáze bez jakýchkoli změn logiky. Podobnou funkcionalitu se pokusily realizovat moderní komerční SGBD (zejména Oracle a Microsoft SQL Server). Na konci článku ukážu, co se jim povedlo, mírně řečeno, ne příliš.

Popis

Jak jsem uvedl dříve, pro lepší pochopení začnu popisovat na příkladech. Předpokládejme, že potřebujeme realizovat logiku, která vrátí seznam oddělení s počtem zaměstnanců a jejich celkovým platem.

Ve funkční databázi by to vypadalo následovně:

CLASS Department 'Oddělení';
name 'Název' = DATA STRING[100] (Oddělení);

CLASS Employee ‘Zaměstnanec’;
department ‘Oddělení’ = DATA Department (Employee);
salary ‘Plat’ = DATA NUMERIC[10,2] (Employee);

countEmployees ‘Počet zaměstnanců’ (Department d) = 
    GROUP SUM 1 IF department(Employee e) = d;
salarySum ‘Celkový plat’ (Department d) = 
    GROUP SUM salary(Employee e) IF department(e) = d;

SELECT name(Department d), countEmployees(d), salarySum(d);

Složitost vykonání tohoto dotazu v jakémkoli SGBD bude ekvivalentní O(počet zaměstnanců), neboť k tomuto výpočtu je třeba proskenovat celou tabulku zaměstnanců a poté je seskupit podle oddělení. Také bude existovat nějaké malé (předpokládáme, že zaměstnanců je mnohem více než oddělení) zvýšení v závislosti na zvoleném plánu O(log počtu zaměstnanců) nebo O(počet oddělení) na seskupení a další.

Je jasné, že režijní náklady na vykonání se mohou lišit v různých SGBD, ale složitost se nijak nezmění.

V navržené implementaci funkční SGBD vytvoří jeden poddotaz, který vypočítá potřebné hodnoty podle oddělení, a poté provede JOIN s tabulkou oddělení pro získání názvu. Nicméně, při deklaraci každé funkce je možné zadat speciální značku MATERIALIZED. Systém automaticky vytvoří odpovídající pole pro každou takovou funkci. Při změně hodnoty funkce bude ve stejné transakci změněna i hodnota pole. Při volání této funkce se bude již obracet na předpočítané pole.

Zejména pokud je pro funkce nastavena možnost MATERIALIZED pocetZamestnancu a sumaMzdy, pak se do tabulky se seznamem oddělení přidají dvě pole, ve kterých budou uchovávány počty zaměstnanců a jejich celkové mzdy. Při jakékoli změně zaměstnanců, jejich mezd nebo příslušnosti k oddělením systém automaticky aktualizuje hodnoty těchto polí. Výše uvedený dotaz se pak bude obracet přímo na tato pole a bude proveden za O(počet oddělení).

Jaká jsou omezení? Pouze jedno: taková funkce musí mít konečný počet vstupních hodnot, pro které je její hodnota určena. Jinak nebude možné sestavit tabulku, která by uchovávala všechny její hodnoty, protože nemůže existovat tabulka s nekonečným počtem řádků.

Příklad:

employeesCount 'Počet zaměstnanců s platem > N' (oddělení d, NUMERIC[10,2] N) = 
    GROUP SUM plat(Employee e) IF oddělení(e) = d AND plat(e) > N;

Tato funkce je definována pro nekonečný počet hodnot čísla N (například jakákoli záporná hodnota). Proto ji nelze označit jako MATERIALIZED. To je tedy logické, nikoli technické omezení (tj. ne proto, že bychom to nedokázali implementovat). Jinak žádná omezení. Lze použít seskupování, řazení, AND a OR, PARTITION, rekurze atd.

Například v úloze 2.2 předchozího článku lze nastavit MATERIALIZED na obě funkce:

zakoupeno 'Zakoupil' (Zákazník c, Produkt p, CELOČÍSELNÉ y) = 
    SKUPINOVÁ SUMA suma(Detail d) POKUD 
        zákazník(příkaz(d)) = c A 
        produkt(d) = p A 
        extractYear(date(order(d))) = y MATERIALIZED;
hodnocení 'Hodnocení' (Zákazník c, Produkt p, CELOČÍSELNÉ y) = 
    PARTITION SUM 1 ORDER DESC bought(c, p, y), p BY c, y MATERIALIZED;
VYBERTE jménoKontaktu(Zákazník c), jméno(Produkt p) KDE hodnocení(c, p, 1997) < 3;

Systém automaticky vytvoří jednu tabulku s klíči typů Zákazník, Produkt a INTEGER, přidá do ní dvě pole a bude aktualizovat jejich hodnoty při jakýchkoli změnách. Při dalších voláních těchto funkcí nebude docházet k jejich výpočtu, ale budou se číst hodnoty z odpovídajících polí.

Pomocí tohoto mechanismu lze například eliminovat rekurze (CTE) v dotazech. Konkrétně zvažme skupiny, které vytvářejí strom pomocí vztahu child/parent (každá skupina má odkaz na svého rodiče):

rodič = DATA Skupina (Skupina);

V funkční databázi lze logiku rekurze definovat následujícím způsobem:

úroveň (skupina dítě, skupina rodič) = REKURZE 1l POKUD dítě JE Skupina A rodič == dítě
                                                             KROK 2l POKUD rodič == rodič($parent);
isParent (skupina dítě, skupina rodič) = PRAVDA POKUD úroveň(dítě, rodič) MATERIALIZOVANÁ;

Jelikož je pro funkci isParent nastaven MATERIALIZED, bude pod ní vytvořena tabulka se dvěma klíči (skupinami), ve které bude pole isParent pravdivé pouze tehdy, pokud je první klíč potomkem druhého. Počet záznamů v této tabulce bude roven počtu skupin vynásobenému průměrnou hloubkou stromu. Pokud je například třeba spočítat počet potomků určité skupiny, lze se obrátit na tuto funkci:

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

Žádné CTE v SQL dotazu přitom nebude. Místo toho dojde k jednoduchému GROUP BY.

Pomocí tohoto mechanismu lze také snadno provádět denormalizaci databáze podle potřeby:

CLASS Order 'Objednávka';
datum 'Datum' = DATA DATE (Objednávka);

CLASS OrderDetail 'Řádek objednávky';
order 'Objednávka' = DATA Order (OrderDetail);
date 'Datum' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;

Při volání funkce date pro řádek objednávky bude probíhat čtení z tabulky s řádky objednávek pole, pro které existuje index. Při změně data objednávky systém sám automaticky přepočítá denormalizované datum v řádku.

Výhody

K čemu je tento mechanismus potřebný? V klasických DBMS, bez přepisování dotazů, mohou vývojáři nebo DBA pouze měnit indexy, určovat statistiku a dávat plánovači dotazů rady, jak je vykonávat (přitom HINTy existují pouze v komerčních DBMS). Ať se snaží jakkoli, nebudou schopni první dotaz v článku provést za O (počet oddělení) bez změny dotazů a psaní triggerů. Ve navrhovaném schématu může vývojář v průběhu vývoje nerušeně přemýšlet o struktuře ukládání dat a o tom, jaké agregace použít. To všechno lze klidně měnit za běhu přímo v provozu.

V praxi to vypadá následovně. Někteří lidé vyvíjejí přímo logiku na základě zadaného úkolu. Nerozumí ani algoritmům a jejich složitosti, ani plánům vykonávání, ani typům joinů, ani žádné jiné technické části. Tito lidé jsou spíše byznys analytici než vývojáři. Poté všechno putuje do testování nebo provozu. Aktivuje se logování dlouhých dotazů. Když se zjistí dlouhý dotaz, rozhodnutí o zapnutí MATERIALIZED na nějaké mezifunkci je přijato jinými lidmi (více technickými — v podstatě DBA). Tím se mírně zpomalí zápis (protože je třeba aktualizovat další pole v transakci). Nicméně, výrazně se urychlí nejen tento dotaz, ale i všechny ostatní, které tuto funkci používají. Přitom je rozhodování o tom, kterou funkci materializovat, relativně jednoduché. Dva hlavní parametry: počet možných vstupních hodnot (přesně tolik záznamů bude v odpovídající tabulce) a jak často je používána v jiných funkcích.

Alternativy

V moderních komerčních DBMS existují podobné mechanismy: MATERIALIZED VIEW s FAST REFRESH (Oracle) a INDEXED VIEW (Microsoft SQL Server). V PostgreSQL MATERIALIZED VIEW není schopen se aktualizovat v transakci, pouze na vyžádání (a navíc s velmi přísnými omezeními), takže jej nebudeme zvažovat. Mají však několik problémů, které značně omezují jejich využití.

Za prvé, materializaci můžete zahrnout pouze tehdy, pokud jste již vytvořili běžný VIEW. Jinak budete muset přepsat ostatní dotazy pro přístup k nově vytvořenému zobrazení, abyste využili tuto materializaci. Nebo můžete všechno nechat, jak je, ale bude to minimálně neefektivní, pokud existují určité předpočítané údaje, které však ne všechny dotazy vždy využívají, ale vypočítávají znovu.

Za druhé, mají obrovské množství omezení:

Oracle

5.3.8.4 Obecná omezení na rychlé obnovení

Definující dotaz materializovaného zobrazení je omezen následujícím způsobem:

  • Materializované zobrazení nesmí obsahovat odkazy na neopakující se výrazy jako SYSDATE and ROWNUM.
  • Materializované zobrazení nesmí obsahovat odkazy na RAW or LONG RAW datové typy.
  • Nesmí obsahovat nebude prováděn při nepravdivosti první podmínky. Opravy pomocí poddotaz z seznamu.
  • Nesmí obsahovat analytické funkce (například, RANK) v nebude prováděn při nepravdivosti první podmínky. Opravy pomocí klauzuli.
  • Nesmí odkazovat na tabulku, na které je definován XMLIndex index.
  • Nesmí obsahovat MODEL klauzuli.
  • Nesmí obsahovat klauzule s poddotazem. Nesmí obsahovat vnořené dotazy, které mají
  • , nebo Zní to poněkud šíleně, ale na schématu — je to jednoduché., ALL[START WITH …] CONNECT BY NOT EXISTS.
  • Nesmí obsahovat Nesmí obsahovat více detailních tabulek na různých místech. klauzuli.
  • Materializovaná zobrazení nemohou mít vzdálené detailní tabulky.
  • NA COMMIT Vnořená materializovaná zobrazení musí mít spojení nebo agregaci.
  • Materializovaná spojení a materializované agregační pohledy s
  • GROUP BY klauzulí nemohou vybírat z tabulky organizované podle indexu. 5.3.8.5 Omezení na rychlé obnovení u materializovaných zobrazení pouze se spoji

Definující dotazy pro materializovaná zobrazení pouze se spoji a bez agregací mají následující omezení na rychlé obnovení:

Všechna omezení z „

  • Obecná omezení na rychlé obnoveníNemohou mít«.
  • klauzule nebo agregace. BY klauzulí nemohou vybírat z tabulky organizované podle indexu. Rowid všech tabulek v
  • seznamu musí být uveden v FROM seznamu dotazu. nebude prováděn při nepravdivosti první podmínky. Opravy pomocí Logy materiálového zobrazení musí existovat s rowid pro všechny základní tabulky v
  • Není možné vytvořit materializované zobrazení obnovitelné rychle z více tabulek s jednoduchými spoji, které zahrnují sloupec typu objektu v FROM Logy materiálového zobrazení musí existovat s rowid pro všechny základní tabulky v
  • prohlášení. nebude prováděn při nepravdivosti první podmínky. Opravy pomocí Také metoda obnovení, kterou si vyberete, nebude optimálně efektivní, pokud:

Definující dotaz používá vnější spojení, které se chová jako vnitřní spojení. Pokud definující dotaz obsahuje takové spojení, zvažte přepsání definujícího dotazu na vnitřní spojení.

  • seznam materializovaného zobrazení obsahuje výrazy na sloupcích z více tabulek.
  • The nebude prováděn při nepravdivosti první podmínky. Opravy pomocí 5.3.8.6 Omezení na rychlé obnovení u materializovaných zobrazení s agregacemi

Definující dotazy pro materializovaná zobrazení s agregacemi nebo spoji mají následující omezení na rychlé obnovení:

Rychlé obnovení je podporováno pro oba

DEMAND NA COMMIT and NA materializované zobrazení, nicméně platí následující omezení: Všechny tabulky v materializovaném zobrazení musí mít logy materializovaného zobrazení a logy materializovaného zobrazení musí:

  • Obsahovat všechny sloupce z tabulky uvedené v materializovaném zobrazení.
    • Uvedeno s
    • ROWID ZAHŔNUJÍCÍ and NOVÉ Uveďte klauzuli, pokud se očekává, že tabulka bude mít směs vkládání/přímého načítání, mazání a aktualizací. VALUES.
    • Pouze SEQUENCE SUM

  • STDDEV VARIANCE, COUNT, AVG, MAX, jsou podporovány pro rychlé obnovení., MIN and COUNT(*) musí být uvedeno.
  • COUNT(*) must be specified.
  • Agregační funkce mohou být použity pouze jako nejvnější část výrazu. To znamená, že agregáty jako AVG(AVG(x)) or AVG(x)+ AVG(x) nejsou povoleny.
  • Pro každý agregát, jako je AVG(expr), musí být přítomno odpovídající COUNT(expr) . Společnost Oracle doporučuje, aby SUM(expr) byla určena.
  • Pokud VARIANCE(expr) or STDDEV(expr) je určena, COUNT(expr) and SUM(expr) musí být určena. Společnost Oracle doporučuje, aby SUM(expr * expr) byla určena.
  • The nebude prováděn při nepravdivosti první podmínky. Opravy pomocí sloupec v definujícím dotazu nemůže být komplexním výrazem s sloupci z více základních tabulek. Možným řešením je použít vnořený materializovaný pohled.
  • The nebude prováděn při nepravdivosti první podmínky. Opravy pomocí seznam musí obsahovat všechny BY klauzulí nemohou vybírat z tabulky organizované podle indexu. sloupce.
  • Materializovaný pohled není založen na jedné nebo více vzdálených tabulkách.
  • Pokud používáte CHAR datový typ ve filtračních sloupcích protokolu materializovaného pohledu, znakové sady hlavního místa a materializovaného pohledu musí být stejné.
  • Pokud má materializovaný pohled jedno z následujících, pak je rychlé obnovení podporováno pouze u konvenčních DML vkládání a přímých načtení.
    • Materializované pohledy s MIN or COUNT(*) agregáty
    • Materializované pohledy, které mají SUM(expr) ale nemají COUNT(expr)
    • Materializované pohledy bez COUNT(*)

    Takový materializovaný pohled se nazývá pouze vkládací materializovaný pohled.

  • Materializovaný pohled s COUNT(*) or MIN je rychle obnovitelný po odstranění nebo smíšených DML příkazech, pokud nemá není spolehlivý: klauzuli.
    Max/min rychlé obnovení po odstranění nebo smíšeném DML nemá stejné chování jako případ pouze vkládající. Odstraní a přepočítá maximální/minimální hodnoty pro dotčené skupiny. Musíte být obezřetní vůči dopadu na výkon.
  • Materializované pohledy s pojmenovanými pohledy nebo poddotazy v FROM klauzuli mohou být rychle obnovitelné, pokud lze pohledy zcela sloučit. Informace o tom, které pohledy se sloučí, naleznete v Oracle Database SQL Language Reference.
  • Pokud nejsou žádné vnější spojení, můžete mít libovolné výběry a spojení v není spolehlivý: klauzuli.
  • Materializované agregační pohledy s vnějšími spojeními jsou rychle obnovitelné po konvenčním DML a přímých načteních, pokud byla upravena pouze vnější tabulka. Také musí existovat jedinečné omezení na spojovacích sloupcích tabulky s vnitřním spojení. Pokud jsou zde vnější spojení, všechna spojení musí být spojena pomocí As a musí používat rovnost (=) operátor.
  • Pro materializované pohledy s CUBE, ROLLUP, skupinové sady nebo jejich spojení platí následující omezení:
    • The nebude prováděn při nepravdivosti první podmínky. Opravy pomocí seznam by měl obsahovat skupinový rozlišovač, který může být buď GROUPING_ID funkcí pro všechny BY klauzulí nemohou vybírat z tabulky organizované podle indexu. výrazy nebo GROUPING funkcemi, každou pro každý BY klauzulí nemohou vybírat z tabulky organizované podle indexu. výraz. Například, pokud klauzule materializovaného pohledu je „ BY klauzulí nemohou vybírat z tabulky organizované podle indexu. CUBE(a, b)BY klauzulí nemohou vybírat z tabulky organizované podle indexu. “, pak by měl seznam obsahovat buď „GROUPING_ID(a, b) nebude prováděn při nepravdivosti první podmínky. Opravy pomocí “ nebo „GROUPING(a)GROUPING(b)“ pro to, aby byl materializovaný pohled rychle obnovitelný. A by neměl vést k žádným duplicitním skupinám. Například, „GROUP BY a, ROLLUP(a, b)
    • BY klauzulí nemohou vybírat z tabulky organizované podle indexu. “ není rychle obnovitelné, protože vede k duplicitním skupinám „(a), (a, b) A (a)5.3.8.7 Omezení na rychlé obnovení u materializovaných pohledů s UNION ALLMaterializované pohledy s«.

operátorem množiny podporují

REFRESH UNION ALL FAST možnost, pokud jsou splněny následující podmínky: Definující dotaz musí mít operátor na nejvyšší úrovni.

  • operátor nemůže být vložen do poddotazu, s jednou výjimkou: " UNION ALL může být v poddotazu v

    The UNION ALL klauzuli, pokud je definující dotaz ve tvaru UNION ALL SELECT * FROM FROM (pohled nebo poddotaz s ) jako v následujícím příkladu: 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 customers c WHERE c.cust_last_name = 'Jones');CREATE MATERIALIZED VIEW unionall_inside_view_mv REFRESH FAST ON DEMAND AS SELECT * FROM view_with_unionall; UNION ALLVšimněte si, že pohled

    view_with_unionall
    

    splňuje požadavky na rychlé obnovení. Každý blok dotazu v dotazu musí splňovat požadavky rychle obnovitelného materializovaného pohledu s agregáty nebo rychle obnovitelného materializovaného pohledu s spojeními.

  • Musí být vytvořeny odpovídající protokoly materializovaného pohledu na tabulkách, jak je požadováno pro odpovídající typ rychle obnovitelného materializovaného pohledu. UNION ALL query must satisfy the requirements of a fast refreshable materialized view with aggregates or a fast refreshable materialized view with joins.

    The appropriate materialized view logs must be created on the tables as required for the corresponding type of fast refreshable materialized view.
    Všimněte si, že Oracle Database také umožňuje zvláštní případ jediné materializované pohledy na tabulku s pouze spojeními, pokud je sloupec zahrnut v ZAHŔNUJÍCÍ seznamu a v deníku materializovaného pohledu. To je zobrazeno v definičním dotazu pohledu nebude prováděn při nepravdivosti první podmínky. Opravy pomocí seznam každého dotazu musí zahrnovat Každý blok dotazu v.

  • The nebude prováděn při nepravdivosti první podmínky. Opravy pomocí značku a sloupec musí mít odlišnou konstantní numerickou nebo textovou hodnotu v každé UNION ALL větvi. Dále, sloupec značky musí být ve stejné pořadí v UNION ALL seznamu každého bloku dotazu. Viz « UNION ALL UNION ALL Značka a Přepis dotazu nebude prováděn při nepravdivosti první podmínky. Opravy pomocí » pro více informací ohledněznaček.Některé funkce jako vnější spojení, dotazy s agregovanými materializovanými pohledy pouze pro vkládání a vzdálené tabulky nejsou podporovány pro materializované pohledy s UNION ALL . Nezapomeňte však, že materializované pohledy používající replikaci, které neobsahují spojení nebo agregace, lze rychle obnovit, pokud
  • nebo vzdálené tabulky jsou použity. UNION ALLParametr inicializace kompatibility musí být nastaven na 9.2.0 nebo vyšší pro vytvoření rychle obnovitelného materializovaného pohledu s UNION ALL Nechci urazit fanoušky Oracle, ale podle jejich seznamu omezení to vypadá, že tento mechanismus byl napsán ne z pohledu obecného případu, s použitím nějakého modelu, ale tisíci Indy, kde každý měl napsat svou vlastní větev a každý z nich udělal, co mohl. Používání tohoto mechanismu pro skutečnou logiku je jako chůze po minovém poli. V každém okamžiku můžete narazit na minu, když se dotknete jednoho z ne zcela zjevného omezení. Jak to funguje — to je také samostatná otázka, ale ta je mimo rámec tohoto článku.
  • Dodatečné požadavky UNION ALL.

Kromě požadavků na nastavení parametrů a deterministických funkcí je třeba splnit následující požadavky:

Microsoft SQL Server

Uživatel, který vykonává

musí být vlastníkem pohledu.

  • Při vytváření indexu musí být možnost CREATE INDEX IGNORE_DUP_KEY
  • nastavena na VYPNUTO (výchozí nastavení). Tabulky musí být odkazovány pomocí dvoudílných názvů, tablename
  • v definici pohledu. schema.Uživatelsky definované funkce odkazované v pohledu musí být vytvořeny pomocí WITH SCHEMABINDING
  • možnost. Jakékoli uživatelsky definované funkce odkazované v pohledu musí být odkazovány pomocí dvoudílných názvů, <schema>
  • <function> Datový přístup vlastnost uživatelsky definované funkce musí být.NO SQL.
  • , a externí přístupová vlastnost musí být NOFunkce běhového prostředí společného jazyka (CLR) mohou být uvedeny v seznamu výběru pohledu, ale nemohou být součástí definice klíče clustered indexu. Funkce CLR nesmějí být uvedeny v klauzuli WHERE pohledu nebo v klauzuli ON operace JOIN v pohledu. Funkce CLR a metody CLR uživatelsky definovaných typů použité v definici pohledu musí mít nastaveny vlastnosti tak, jak je uvedeno v následující tabulce..
  • DETERMINISTIC = TRUE
  • Musí být výslovně deklarováno jako atribut metody Microsoft .NET Framework.

    Vlastnost
    Note

    PRECISE = TRUE
    Musí být výslovně deklarováno jako atribut metody .NET Framework.

    DATA ACCESS = NO SQL
    Určeno nastavením atributu DataAccess na DataAccessKind.None a atributu SystemDataAccess na SystemDataAccessKind.None.

    EXTERNAL ACCESS = NO
    Tato vlastnost ve výchozím nastavení je NO pro CLR rutiny.

    Pohled musí být vytvořen pomocí
    Pohled musí odkazovat pouze na základní tabulky, které jsou ve stejné databázi jako pohled. Pohled nesmí odkazovat na jiné pohledy.

  • Dotaz SELECT v definici pohledu nesmí obsahovat následující prvky Transact-SQL: Jakékoli uživatelsky definované funkce odkazované v pohledu musí být odkazovány pomocí dvoudílných názvů, <schema>
  • Funkce ROWSET (
  • OPENDATASOURCE

    COUNT
    OPENQUERYOPENROWSET, , A, OPENXMLVnější spojení ()
    LEVÝ PRAVÝPLNÝ, Odvozená tabulka (definovaná specifikováním[START WITH …] CONNECT BY předpisu v klauzuli))

    Sebezapojení nebude prováděn při nepravdivosti první podmínky. Opravy pomocí Specifikování sloupců pomocí FROM SELECT *
    SELECT <table_name>.*
    STDEV STDEVP or VAR

    DISTINCT
    VARP, Společný tabulkový výraz (CTE), ntext, ntext[START WITH …] CONNECT BY AVG
    ntext

    float1, text, ntext, obrázek, XML[START WITH …] CONNECT BY filestream sloupce
    Poddotaz
    NAD klauzule, která zahrnuje hodnotící nebo agregační oknové funkce

    Predikáty pro úplný text (OBSAHUJE, FREETEXT)
    VARIANCE funkce, která odkazuje na nullable výraz
    ORDER BY

    CLR uživatelsky definovaná agregační funkce
    TOP
    CUBE, ROLLUP[START WITH …] CONNECT BY SADY SKUPINOVÁNÍ operátory

    MIN, COUNT(*)
    UNION, KROMĚ[START WITH …] CONNECT BY INTERSECT operátory
    VZOREK TABULKY

    Tabulkové proměnné
    VONNÝ APLIKACE or CROSS APPLY
    PIVOT, UNPIVOT

    Sady sparse sloupců
    Inline (TVF) nebo více-statement table-valued funkce (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Indexovaný pohled může obsahovat float sloupce; nicméně takové sloupce nemohou být zahrnuty do klíče clustered indexu.

  • Pokud GROUP BY je-li přítomen, definice VIEW musí obsahovat COUNT_BIG(*) a nesmí obsahovat klauzule s poddotazem.. Tyto GROUP BY omezení se vztahují pouze na definici indexovaného pohledu. Dotaz může použít indexovaný pohled v jeho plánování exekuce, i když tato GROUP BY omezení. Pokud definice pohledu obsahuje
  • klauzuli, může klíč unikátního clustered indexu odkazovat pouze na sloupce uvedené v GROUP BY Je jasné, že Indy to nezajímalo, protože se rozhodli udělat to podle schématu "uděláme málo, ale dobře". To znamená, že mají více min na poli, ale jejich umístění je transparentnější. Nejvíce mrzí toto omezení: GROUP BY klauzuli.

V naší terminologii to znamená, že funkce nemůže odkazovat na jinou materializovanou funkci. To podkopává celou ideologii.

Funkce ROWSET (

Toto omezení (a dále v textu) značně snižuje možnosti použití:
Zakázány jsou OUTER JOINS, UNION, ORDER BY a další. Možná by bylo jednodušší uvést, co lze použít, než to, co nelze. Seznam by pravděpodobně byl mnohem menší.

OPENDATASOURCE

COUNT
OPENQUERYOPENROWSET, , A, OPENXMLVnější spojení ()
LEVÝ PRAVÝPLNÝ, Odvozená tabulka (definovaná specifikováním[START WITH …] CONNECT BY předpisu v klauzuli))

Sebezapojení nebude prováděn při nepravdivosti první podmínky. Opravy pomocí Specifikování sloupců pomocí FROM SELECT *
SELECT <table_name>.*
STDEV STDEVP or VAR

DISTINCT
VARP, Společný tabulkový výraz (CTE), ntext, ntext[START WITH …] CONNECT BY AVG
ntext

float1, text, ntext, obrázek, XML[START WITH …] CONNECT BY filestream sloupce
Poddotaz
NAD klauzule, která zahrnuje hodnotící nebo agregační oknové funkce

Predikáty pro úplný text (OBSAHUJE, FREETEXT)
VARIANCE funkce, která odkazuje na nullable výraz
ORDER BY

CLR uživatelsky definovaná agregační funkce
TOP
CUBE, ROLLUP[START WITH …] CONNECT BY SADY SKUPINOVÁNÍ operátory

MIN, COUNT(*)
UNION, KROMĚ[START WITH …] CONNECT BY INTERSECT operátory
VZOREK TABULKY

Tabulkové proměnné
VONNÝ APLIKACE or CROSS APPLY
PIVOT, UNPIVOT

Sady sparse sloupců
Inline (TVF) nebo více-statement table-valued funkce (MSTVF)
OFFSET

CHECKSUM_AGG

Ve zjednodušeném závěru: obrovský soubor omezení v každé (zdůrazňuji obchodní) DBMS vs. žádná (kromě jednoho logického, nikoli technického) v LGPL technologii. Je však třeba poznamenat, že implementace tohoto mechanismu v relační logice je poněkud složitější než v popsané funkční.

Jak to funguje? Jako "virtuální stroj" se používá PostgreSQL. Uvnitř existuje složitý algoritmus, který se zabývá sestavováním dotazů. Tady

Implementace

. A tam není jen velké množství heuristik s hromadou if'ů. Takže, pokud máte pár měsíců na studium, můžete to zkusit pochopit architekturu. zdrojový kód. И там не просто большой набор эвристик с кучей if’ов. Так что, если есть пару месяцев на изучение, то можете попробовать разобраться в архитектуре.

Funguje to efektivně? Dostatečně efektivně. Bohužel, důkaz toho je těžký. Mohu jen říci, že když vezmete v úvahu tisíce dotazů, které existují ve velkých aplikacích, tak průměrně jsou efektivnější než u dobrého vývojáře. Skvělý SQL programátor může napsat jakýkoli dotaz efektivněji, ale u tisíce dotazů nemá motivaci ani čas to udělat. Jediné, co mohu nyní uvést jako důkaz efektivity, je to, že na platformě postavené na této DBMS běží několik projektů ERP systémy, ve kterých je tisíce různých MATERIALIZED funkcí, s tisíci uživateli a terabajtovými databázemi se stovkami milionů záznamů, které běží na běžném dvouprocesorovém serveru. Každý, kdo chce, může efektivitu ověřit/vyvrátit stažením platformu a PostgreSQL, přičemž je třeba logováním SQL dotazů a pokusit se změnit logiku a data tam.

V následujících článcích také povím o tom, jak lze omezit funkce, pracovat se sezeními změn a mnohem více.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster