Балансировка на записите и четенето в база данни

Балансировка на записите и четенето в база данни
В предишната статии Описах концепцията и реализирането на база данни, построена на основа функции, а не таблици и полета как в релационните бази данни. В нея бяха приведени множество примери, показващи предимствата на такъв подход пред класическия. Много хора ги намериха недостатъчно убедителни.

В тази статия ще покажа как такава концепция позволява бързо и удобно балансиране на записите и четенето в база данни без каквото и да било изменение на логиката на работа. Подобен функционал се опита да бъде реализиран в съвременните търговски СУБД (в частност, Oracle и Microsoft SQL Server). В края на статията ще покажа какво постигнаха те, меко казано, не особено успешно.

Описание

Както и преди, за по-добро разбиране ще започна описанието с примери. Да предположим, че трябва да реализираме логика, която ще връща списък на отделите с броя на служителите в тях и техния общ доход.

В функционалната база данни това ще изглежда по следния начин:

КЛАС Отдел;
име ‘Наименование’ = ДАННИ СТРИНГ[100] (Отдел);

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

Сложността на изпълнението на този запит в която и да е СУБД ще бъде равна на O(брой служители), тъй като за това изчисление е необходимо да се прегледа цялата таблица на служителите, а след това да се групират по отдел. Също така ще има някаква малка (да приемем, че служителите са значително повече от отделите) добавка в зависимост от избрания план. O(log брой служители) или O(брой отдели) за групировка и друго.

Ясно е, че разходите за изпълнение могат да бъдат различни в различни СУБД, но сложността няма да се промени по никакъв начин.

В предложената реализация функционалната СУБД ще генерира една под-заявка, която ще изчисли необходимите стойности по отдели, след което ще направи JOIN с таблицата на отделите, за да получи името. Въпреки това, за всяка функция при декларирането има възможност да зададете специален маркер MATERIALIZED. Системата автоматично ще създаде съответно поле за всяка такава функция. При промяна на стойността на функцията, стойността на полето ще се променя в същата транзакция. При достъп до тази функция ще се извършва достъп до предварително изчисленото поле.

По-специално, ако зададете MATERIALIZED за функциите countEmployees и salarySum, тогава в таблицата със списъка на отделите ще бъдат добавени две полета, в които ще се съхраняват броя на служителите и тяхната обща заплата. При всяка промяна на служителите, техните заплати или принадлежността им към отделите, системата автоматично ще променя стойностите на тези полета. Посочената по-горе заявка ще се обръща директно към тези полета и ще се изпълни за O(брой отдели).

Какви ограничения има? Само едно: такова функция трябва да има крайно число входни стойности, за които стойността ѝ е определена. В противен случай няма да е възможно да се построи таблица, съхраняваща всичките ѝ стойности, тъй като не може да има таблица с безкрайно количество редове.

Пример:

employeesCount ‘Брой на служителите с заплата > N’ (Отдел d, NUMERIC[10,2] N) = 
    GROUP SUM salary(Служител e) IF department(e) = d AND salary(e) > N;

Тази функция е определена за безкрайно количество стойности на числото N (например, всяко отрицателно значение подхожда). Следователно, не може да се зададе MATERIALIZED за нея. По този начин, това е логично, а не техническо ограничение (тоест не защото не сме могли да го реализираме). В останалото — няма ограничения. Можете да използвате групировки, сортирания, AND и OR, PARTITION, рекурсии и т.н.

Например, в задача 2.2 от предишната статия можете да зададете MATERIALIZED за двете функции:

Купил 'Купил' (Клиент c, Продукт p, ЦЕЛО число y) = 
    ГРУПА СУМ sum(Детайл d) IF 
        клиент(поръчка(d)) = c И 
        продукт(d) = p И 
        извлечиГодина(дата(поръчка(d))) = y МАТЕРИАЛИЗИРАНО;
рейтинг 'Рейтинг' (Клиент c, Продукт p, ЦЕЛО число y) = 
    ЧАСТИРАНЕ СУМ 1 НАРЕЖДАНЕ ОНД ПРЕДПРИЕТО(c, p, y), p ПО c, y МАТЕРИАЛИЗИРАНО;
ИЗБЕРЕТЕ контактноИме(Клиент c), име(Продукт p) КЪДЕТО рейтинг(c, p, 1997) < 3;

Системата сама ще създаде една таблица с ключове от типове Клиент, Продукт и INTEGER, ще добави в нея две полета и ще обновява стойностите на полетата при всякакви промени. При по-нататъшни извиквания на тези функции, техният изчисление няма да се извършва, а ще се четат стойностите от съответните полета.

С помощта на този механизъм можете, например, да се избавите от рекурсиите (CTE) в заявките. По-специално, да разгледаме групите, които образуват дърво чрез отношението child/parent (всяка група има връзка със своя родител):

родител = DATA Group (Group);

В функционалната база данни логиката на рекурсията може да се зададе по следния начин:

nivå (Gruppa детенце, Gruppa родител) = РЕКУРСИЯ 1l АКО детенцето Е Gruppa И родител == детенцето
                                                             СТЪПКА 2l АКО родител == родител($parent);
еРодител (Gruppa детенце, Gruppa родител) = Вярно АКО nivå(детенце, родител) МАТЕРИАЛИЗИРАНО;

Тъй като за функцията isParent е зададен MATERIALIZED, то за нея ще бъде създадена таблица с два ключа (групи), в която полето isParent ще бъде истинно само ако първият ключ е потомък на втория. Броят на записите в тази таблица ще бъде равен на броя на групите, умножен по средната дълбочина на дървото. Ако е необходимо, например, да се изчисли броят на потомците на определена група, може да се обърнете към тази функция:

childrenCount (Група g) = GROUP SUM 1 IF isParent(Група child, g);

Няма да има CTE в SQL заявката. Вместо това ще бъде прост GROUP BY.

С помощта на този механизъм може да се направи лесна денормализация на базата данни при необходимост:

CLASS Order 'Поръчка';
date 'Дата' = DATA DATE (Order);

CLASS OrderDetail 'Ред за поръчка';
order 'Поръчка' = DATA Order (OrderDetail);
date 'Дата' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;

При повикване на функцията date за реда на поръчката ще се извършва четене от таблицата с редове за поръчки на полето, за което има индекс. При промяна на датата на поръчката системата автоматично ще прерасчита денормализираната дата в реда.

Предимства

За какво е необходим този механизъм? В класическите СУБД, без преизписване на заявките, разработчикът или DBA могат само да променят индексите, да определят статистиката и да дават насоки на планирача на заявки как да ги изпълнява (като HINT-ите съществуват само в търговските СУБД). Каквото и да правят, те няма да могат да изпълнят първата заявка в статията за O (броя на отделите) без да променят заявките и без добавяне на тригери. В предложената схема, на етапа на разработка не е необходимо да се мисли за структурата на съхранение на данните и какви агрегации да се използват. Всичко това може спокойно да се променя на място в експлоатацията.

На практика това изглежда по следния начин. Някои хора създават логика въз основа на определена задача. Те не разбират ни алгоритми, ни тяхната сложност, ни плановете за изпълнение, ни типовете join, нито каквато и да е друга техническа съставка. Тези хора са по-скоро бизнес анализатори, отколкото разработчици. След това всичко това преминава в тестване или експлоатация. Включва се логване на дълги заявки. Когато се открие дълга заявка, решение за включване на MATERIALIZED на определена междинна функция се взема от други хора (по-технически — всъщност DBA). По този начин записът се забавя малко (тъй като е необходимо обновление на допълнителното поле в транзакцията). Въпреки това, не само тази заявка, но и всички останали, които използват тази функция, значително се ускоряват. При това решението за коя точно функция да се материализира се взема сравнително лесно. Два основни параметъра: брой на възможните входни стойности (точно толкова записи ще има в съответната таблица) и колко често се използва в другите функции.

Аналози

В съвременните комерсиални СУБД съществуват подобни механизми: MATERIALIZED VIEW с FAST REFRESH (Oracle) и INDEXED VIEW (Microsoft SQL Server). В PostgreSQL MATERIALIZED VIEW не може да се обновява в транзакция, а само по запитване (може би с много строги ограничения), така че няма да я разглеждаме. Но те имат няколко проблема, които значително ограничават тяхното използване.

На първо място, материализацията може да се включи само, ако вече е създадена обикновена VIEW. В противен случай ще е необходимо да се пренапишат останалите запитвания, за да се обърнат към новосъздаденото представление, за да може да се използва тази материализация. Или да се остави всичко както е, но това ще бъде поне неефективно, ако вече има определени предварително изчислени данни, но много запитвания не винаги ги използват, а ги изчисляват отново.

На второ място, те имат огромно количество ограничения:

Oracle

5.3.8.4 Общи ограничения на бързото обновление

Определящото запитване на материализираното представление е ограничено, както следва:

  • Материализираното представление не трябва да съдържа референции към не повтарящи се изрази като SYSDATE and ROWNUM.
  • Материализираното представление не трябва да съдържа референции към RAW or LONG RAW типове данни.
  • Не може да съдържа SELECT субзаявка в списък.
  • Не може да съдържа аналитични функции (например, RANK) в SELECT клауза.
  • Не може да се позовава на таблица, върху която е дефиниран XMLIndex индекс.
  • Не може да съдържа MODEL клауза.
  • Не може да съдържа клауза HAVING с подзапитване. Не може да съдържа вложени запитвания, които имат
  • ANY , или, ALL[START WITH …] CONNECT BY NOT EXISTS.
  • Не може да съдържа [START WITH …] СВЪРЗВАНЕ ЧРЕЗ клауза.
  • Не може да съдържа множество детайлни таблици на различни сайтове.
  • ON COMMIT Материализираните изгледи не могат да имат отдалечени детайлни таблици.
  • Вложените материализирани изгледи трябва да имат присъединяване или агрегация.
  • Материализирани присъединяващи изгледи и материализирани агрегационни изгледи с ГРУПА ПО клаузата не може да избира от таблица, организирана по индекс.

5.3.8.5 Ограничения за бързо обновление на материализирани изгледи само с присъединявания.

Определящите запитвания за материализирани изгледи само с присъединявания и без агрегации имат следните ограничения за бързо обновление:

  • Всички ограничения от «Общи ограничения за бързо обновление«.
  • Те не могат да имат ГРУПА ПО клаузи или агрегации.
  • Rowid-ите на всички таблици в FROM списъка трябва да се появят в SELECT списъка на запитването.
  • Логовете на материализираните изгледи трябва да съществуват с rowid-ите за всички основни таблици в FROM списъка на запитването.
  • Не можете да създадете материализиран изглед, който да се обновява бързо от множество таблици с прости присъединявания, които включват колона от тип обект в SELECT изявлението.

Също така, методът за обновление, който изберете, няма да бъде оптимално ефективен, ако:

  • Определящото запитване използва външно присъединяване, което се държи като вътрешно присъединяване. Ако определящото запитване съдържа такова присъединяване, помислете за пренаписване на определящото запитване, за да съдържа вътрешно присъединяване.
  • The SELECT списъкът на материализирания изглед съдържа изрази върху колони от множество таблици.

5.3.8.6 Ограничения за бързо обновление на материализирани изгледи с агрегации.

Определящите запитвания за материализирани изгледи с агрегации или присъединявания имат следните ограничения за бързо обновление:

Бързото обновление се поддържа за двете ON COMMIT and ON ПОИСКВАНЕ материализирани изгледи, обаче следните ограничения се прилагат:

  • Всички таблици в материализирания изглед трябва да имат логове на материализирани изгледи, а логовете на материализирания изглед трябва:
    • Да съдържат всички колони от таблицата, спомената в материализирания изглед.
    • Да се обозначават с ROWID and ВКЛЮЧИТЕЛНО НОВИ VALUES.
    • Да се обозначи ПОСЛЕДОВАТЕЛНОСТ клаузата, ако се очаква, че таблицата ще има смес от вмъквания/директни натоварвания, изтривания и актуализации.

  • Само СУМ, COUNT, AVG, СТДДЕВ, ВАРИАЦИЯ, МИН and MAX са поддържани за бързо обновление.
  • COUNT(*) трябва да бъде указан.
  • Агрегираните функции трябва да се появяват само като най-външната част на израза. Тоест, агрегати като AVG(AVG(x)) or AVG(x)+ AVG(x) не са разрешени.
  • За всеки агрегат, като AVG(expr), съответстващият COUNT(expr) трябва да присъства. Oracle препоръчва, че SUM(expr) да бъде указан.
  • Ако VARIANCE(expr) or СТДДЕВ(expr) се укаже, COUNT(expr) and SUM(expr) трябва да бъде указан. Oracle препоръчва, че SUM(expr * expr) да бъде указан.
  • The SELECT колоната в определящото запитване не може да бъде сложен израз с колони от множество основни таблици. Една възможна алтернатива за това е да се използва вложен материализиран изглед.
  • The SELECT списъкът трябва да съдържа всички ГРУПА ПО колони.
  • Материализираният изглед не е основан на една или повече отдалечени таблици.
  • Ако използвате CHAR тип данни в колоните за филтриране на лог на материализиран изглед, наборите от символи на основния сайт и материализирания изглед трябва да са същите.
  • Ако материализираният изглед има един от следните, тогава бързото обновление се поддържа само при конвенционални DML вмъквания и директни натоварвания.
    • Материализирани изгледи с МИН or MAX агрегати
    • Материализирани изгледи, които имат SUM(expr) но не COUNT(expr)
    • Материализирани изгледи без COUNT(*)

    Такъв материализиран изглед се нарича само-вмъкващ материализиран изглед.

  • Материализираният изглед с MAX or МИН се обновява бързо след изтриване или смесени DML изявления, ако не съдържа WHERE клауза.
    Максималното/минималното бързо обновление след изтриване или смесени DML няма същото поведение като случая при само-вмъквания. Той изтрива и преизчислява максималните/минималните стойности за засегнатите групи. Трябва да сте наясно с неговото влияние върху производителността.
  • Материализирани изгледи с именувани изгледи или подзапитвания в FROM клаузата могат да се обновят бързо при условие, че изгледите могат да бъдат напълно слети. За информация за това кои изгледи ще се слеят, вижте Справочник по SQL езика на Oracle Database.
  • Ако няма външни присъединявания, може да имате произволни селекции и присъединявания в WHERE клауза.
  • Материализирани агрегатни изгледи с външни присъединявания могат да се обновят бързо след конвенционални DML и директни натоварвания, при условие че само външната таблица е била променена. Също така, уникални ограничения трябва да съществуват по колоните на присъединителната таблица в вътрешното присъединяване. Ако има външни присъединявания, всички присъединявания трябва да са свързани. Ии трябва да използва оператора за равенство (=) оператор.
  • За материализирани изгледи с CUBE, ROLLUP, груповите набори или тяхната комбинация, се прилагат следните ограничения:
    • The SELECT списъкът трябва да съдържа уникализатор на групировка, който може да бъде GROUPING_ID функция за всички ГРУПА ПО изрази или GROUPING функции за всеки ГРУПА ПО израз. Например, ако ГРУПА ПО клауза на материализирания изглед е «ГРУПА ПО CUBE(a, b)«, то списъкът трябва да съдържа или « SELECT GROUPING_ID(a, b)» или «GROUPING(a)GROUPING(b) И » за материализирания изглед да бъде бързо обновяем.не трябва да доведе до дублиращи се групировки. Например, «
    • ГРУПА ПО GROUP BY a, ROLLUP(a, b)» не е бързо обновяем, тъй като води до дублиращи се групировки «(a), (a, b), И (a)5.3.8.7 Ограничения по отношение на бързо обновление на материализирани изгледи с UNION ALL«.

Материализирани изгледи с

оператор за множество поддържат UNION ALL REFRESH FAST опцията, ако са изпълнени следните условия: Дефиниращата заявка трябва да има

  • оператор на горно ниво. UNION ALL операторът не може да бъде вграждан в подзаявка, с едно изключение: Този

    The UNION ALL може да бъде в подзаявка в UNION ALL клауза, при условие че дефиниращата заявка е от формата FROM SELECT * FROM (изглед или подзаявка с ) как във следния пример: UNION ALLCREATE 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;

    Обърнете внимание, че изгледът
    

    view_with_unionall спазва изискванията за бързо обновление. Всеки блок от запитването трябва да отговаря на изискванията за бързо обновяем материализиран изглед с агрегати или за бързо обновяем материализиран изглед с обединения.

  • Необходимите материалирани дневници на изгледа трябва да бъдат създадени върху масите, както е необходимо за съответния тип бързо обновяем материализиран изглед. UNION ALL Обърнете внимание, че Oracle Database също позволява специалния случай на материализиран изглед с единствена таблица с обединения само при условие, че

    колоната е била включена в
    списъка и в дневника на материализирания изглед. Това е показано в дефиниращата заявка на изгледа ROWID списъкът на всяко запитване трябва да включва уникализатор, и колоната SELECT трябва да има различителна константна числова или стрингова стойност във всяка спазва изискванията за бързо обновление..

  • The SELECT клонка. Освен това, колоната с уникализатора трябва да се появи на същата поредна позиция в UNION ALL списъка на всеки блок от запитването. Вижте « UNION ALL UNION ALL Marker and Query Rewrite UNION ALL » за повече информация относно SELECT уникализаторите.Някои функции като външни обединения, запитвания за материализирани изгледи само с добавяне на агрегати и отдалечени таблици не са поддържани за материализирани изгледи с. Обаче, материализирани изгледи, използвани в репликация, които не съдържат обединения или агрегати, могат да бъдат бързо обновени, когато UNION ALL или отдалечени таблици се използват.
  • Параметърът за инициализация на съвместимостта трябва да бъде зададен на 9.2.0 или по-висока версия, за да се създаде бързо обновяем материализиран изглед с UNION ALLНе искам да обидя феновете на Oracle, но на базата на техния списък с ограничения, създава се впечатлението, че този механизъм не е написан в общия случай, използвайки някаква моделна схема, а от хиляди индийци, на които е било дадено позволение да напишат своя клон, и всеки е направил каквото е могъл. Използването на този механизъм за реална логика — това е като ходене по мини. Във всякакъв момент може да попаднете на мина, попадайки на едно от неочевидните ограничения. Как функционира — също е отделен въпрос, но той е извън обхвата на настоящата статия. UNION ALL Допълнителни изисквания
  • Освен опции SET и изискванията за детерминирани функции, следните изисквания трябва да бъдат изпълнени: UNION ALL.

Потребителят, който изпълнява

Microsoft SQL Server

Допълнителни изисквания

В допълнение към изискванията за SET опции и детерминирани функции, трябва да бъдат изпълнени следните изисквания:

  • Потребителят, който изпълнява CREATE INDEX трябва да бъдете собственик на изгледа.
  • Когато създавате индекса, IGNORE_DUP_KEY опцията трябва да бъде зададена на ИЗКЛЮЧЕНО (по подразбиране).
  • Таблиците трябва да бъдат посочвани с двусъставни имена, schema.tablename в определението за изгледа.
  • Потребителските функции, посочени в изгледа, трябва да бъдат създадени с WITH SCHEMABINDING опция.
  • Всяка потребителска функция, посочена в изгледа, трябва да бъде посочена с двусъставни имена, <схема>.<функция>.
  • Свойството за достъп до данни на потребителска функция трябва да бъде NO SQL, а свойството за външен достъп трябва да бъде NO.
  • Функции на общия език за програмиране (CLR) могат да се появят в списъка за избор на изгледа, но не могат да бъдат част от определението на ключа на кластеризирания индекс. CLR функции не могат да се появяват в клаузата WHERE на изгледа или в клаузата ON на операция JOIN в изгледа.
  • Функции CLR и методи на потребителски типове, определени от CLR, използвани в определението за изгледа, трябва да имат свойствата зададени по начина, показан в следната таблица.

    Property
    Note

    DETERMINISTIC = TRUE
    Трябва да бъде декларирано изрично като атрибут на метода от Microsoft .NET Framework.

    PRECISE = TRUE
    Трябва да бъде декларирано изрично като атрибут на метода от .NET Framework.

    DATA ACCESS = NO SQL
    Определя се чрез задаване на атрибута DataAccess на DataAccessKind.None и атрибута SystemDataAccess на SystemDataAccessKind.None.

    EXTERNAL ACCESS = NO
    Тази собственост по подразбиране е NO за CLR рутините.

  • Изгледът трябва да бъде създаден с WITH SCHEMABINDING опция.
  • Изгледът трябва да се отнася само за базови таблици, които се намират в същата база данни като изгледа. Изгледът не може да се отнася до други изгледи.
  • SELECT изразът в определението за изгледа не трябва да съдържа следните елементи на Transact-SQL:

    COUNT
    Функции ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, И OPENXML)
    ВЪНШНИ съединения (ЛЯВ, ДЯСЕН[START WITH …] CONNECT BY FULL)

    Производна таблица (определена чрез задаване на SELECT израз в FROM клаузата)
    Самосъединения
    Посочване на колони чрез SELECT * or SELECT <име_на_таблица>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARP[START WITH …] CONNECT BY AVG
    Обща таблица израз (CTE)

    float1, text, ntext, image, XML[START WITH …] CONNECT BY filestream колони
    Подзаявка
    OVER клаузата, която включва функции за класиране или обобщаващи функции за прозорец

    Предикати с пълен текст (CONTAINS, FREETEXT)
    СУМ функция, която се отнася до нулаем израз
    ORDER BY

    CLR потребителска агрегатна функция
    TOP
    CUBE, ROLLUP[START WITH …] CONNECT BY GROUPING SETS оператори

    МИН, MAX
    UNION, EXCEPT[START WITH …] CONNECT BY INTERSECT оператори
    TABLESAMPLE

    Таблични променливи
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Сетове от редове с рядка колона
    Инлайн (TVF) или многоизявление таблици с функции (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Индексираният изглед може да съдържа float колони; обаче, такива колони не могат да бъдат включени в ключа на кластеризирания индекс.

  • Ако GROUP BY ако е налице, определението на ИЗГЛЕДА трябва да съдържа COUNT_BIG(*) и не трябва да съдържа клауза HAVING с подзапитване.. Тези GROUP BY ограничения се прилагат само за определението на индексирания изглед. Запитването може да използва индексирания изглед в плана за изпълнение, дори ако не удоволетворява тези GROUP BY ограничения.
  • Ако определението на изгледа съдържа GROUP BY клаузата, ключът на уникалния кластеризиран индекс може да се отнася само за колоните, посочени в GROUP BY клауза.

Тук е видно, че индийците не са били привлечени, тъй като решиха да действат по схемата "да направим малко, но добре". Тоест те имат повече мини на полето, но разположението им е по-прозрачно. Най-много ме разочарова това ограничение:

Изгледът трябва да се отнася само за базови таблици, които се намират в същата база данни като изгледа. Изгледът не може да се отнася до други изгледи.

В нашата терминология това означава, че функцията не може да се отнася до друга материализирана функция. Това реже цялата идея в корена.
Също така това ограничение (и следващото по текста) намалява много вариантите за използване:

SELECT изразът в определението за изгледа не трябва да съдържа следните елементи на Transact-SQL:

COUNT
Функции ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, И OPENXML)
ВЪНШНИ съединения (ЛЯВ, ДЯСЕН[START WITH …] CONNECT BY FULL)

Производна таблица (определена чрез задаване на SELECT израз в FROM клаузата)
Самосъединения
Посочване на колони чрез SELECT * or SELECT <име_на_таблица>.*

DISTINCT
STDEV, STDEVP, VAR, VARP[START WITH …] CONNECT BY AVG
Обща таблица израз (CTE)

float1, text, ntext, image, XML[START WITH …] CONNECT BY filestream колони
Подзаявка
OVER клаузата, която включва функции за класиране или обобщаващи функции за прозорец

Предикати с пълен текст (CONTAINS, FREETEXT)
СУМ функция, която се отнася до нулаем израз
ORDER BY

CLR потребителска агрегатна функция
TOP
CUBE, ROLLUP[START WITH …] CONNECT BY GROUPING SETS оператори

МИН, MAX
UNION, EXCEPT[START WITH …] CONNECT BY INTERSECT оператори
TABLESAMPLE

Таблични променливи
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Сетове от редове с рядка колона
Инлайн (TVF) или многоизявление таблици с функции (MSTVF)
OFFSET

CHECKSUM_AGG

Забранени са ВЪНШНИ СЪЕДИНЕНИЯ, UNION, ORDER BY и други. Може би е било по-лесно да се посочи какво може да се използва, отколкото какво не може. Списъкът вероятно щеше да бъде много по-кратък.

В заключение: значительное количество ограничений в каждой (отмечу коммерческой) СУБД против отсутствия таковых (за исключением одного логического, а не технического) в технологии LGPL. Однако стоит отметить, что внедрение этого механизма в реляционной логике немного сложнее, чем описано в функциональной.

Реализация

Как это работает? В качестве «виртуальной машины» используется PostgreSQL. Внутри находится сложный алгоритм, занимающийся построением запросов. Вот что. изходния кодИ там не просто обширный набор эвристик с множеством условий. Так что, если у вас есть несколько месяцев на изучение, вы можете попробовать разобраться в архитектуре.

Работает ли это эффективно? Достаточно эффективно. К сожалению, доказать это сложно. Могу лишь сказать, что если рассмотреть тысячи запросов, используемых в крупных приложениях, то в среднем они эффективнее, чем у хорошего разработчика. Отличный SQL-программист может написать любой запрос более эффективно, но на тысяче запросов у него просто не будет ни времени, ни мотивации это делать. Единственное, что могу предложить как доказательство эффективности — это то, что на платформе, созданной на этой СУБД, работают несколько проектов. ERP-системы, в которых существует тысячи различных MATERIALIZED функций, с тысячами пользователей и терабайтными базами данных с сотнями миллионов записей, функционирующими на обычном двухпроцессорном сервере. Тем не менее, любой желающий может проверить или опровергнуть эффективность, скачав платформа и PostgreSQL, включвайки включая логирование SQL-запросов и попробовав изменять там логику и данные.

В следующих статьях я также расскажу о том, как можно накладывать ограничения на функции, работать с сеансами изменений и многое другое.

Източник: habr.com

Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри 🔥 Купете надежден хостинг за сайтове със защита от DDoS, VPS и VDS сървъри | ProHoster