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

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

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

Описание

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

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

CLASS Отдел;
name ‘Наименование’ = DATA STRING[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(брой отдели).

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

Пример:

брой на служителите 'Брой на служителите с заплата > N' (Отдел d, ЧИСЛО[10,2] N) = 
    ГРУПА СУМ salary(Служител e) АКО department(e) = d И salary(e) > N;

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

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

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

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

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

родител = ДАННИ Група (Група);

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

нивото (група дете, група родител) = РЕКУРСИЯ 1л, АКО дете E група И родител == дете
                                                             СТЪПКА 2л, АКО родител == родител($parent);
еРодител (група дете, група родител) = ИСТИНА, АКО нивото(дете, родител) Е РЕАЛИЗИРАНО;

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

броят на децата (Група g) = СУМА НА ГРУПА 1 АКО еРодител(Група дете, g);

В SQL запитването няма да има CTE. Вместо това ще има прост 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'ите съществуват само в търговски СУБД). Колкото и да се стараят, те няма да могат да изпълнят първото запитване в статията за О (брой отдели) без да променят запитванията и да добавят тригери. В предложената схема, на етапа на разработката може да не се мисли за структурата на съхранение на данни и за това, какви агрегации да се използват. Всичко това може спокойно да се променя на място вече по време на експлоатацията.

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

Аналози

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

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

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

Oracle

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

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

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

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

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

  • Всички ограничения от «Общи ограничения на бързо обновяване«.
  • Не могат да имат ГРУПА ЧРЕЗ клауза или агрегати.
  • Rowids на всички таблици в OT списъка трябва да се появяват в SELECT списъка на заявката.
  • Логовете на материализирания изглед трябва да съществуват с rowids за всички базови таблици в OT списъка на заявката.
  • Не можете да създадете материализиран изглед с бързо обновяване от множество таблици с прости съединения, които съдържат колонa от тип обект в SELECT изявлението.

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

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

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

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

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

  • Всички таблици в материализирания изглед трябва да имат логове на материализирани изгледи и логовете трябва:
    • Да съдържат всички колони от таблицата, на която се позовава в материализирания изглед.
    • Да се определи с ROWID и ВКЛ. НОВИ СТОЙНОСТИ.
    • Да се определи БРОЙ клауза, ако се очаква таблицата да има комбинация от вставки/директни зареждания, изтривания и актуализации.

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

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

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

Материализованите изгледи с оператор на множество поддържат

бързо UNION ALL обновление , ако са изпълнени следните условия: Дефиниращата заявка трябва да има оператора на най-високо ниво. оператор не може да бъде вложен в подзаявка, с едно изключение: Операторът

  • може да бъде в подзаявка в UNION ALL клауза, при условие че дефиниращата заявка е от формата

    The UNION ALL SELECT * FROM UNION ALL (изглед или подзаявка с OT ) както в следния пример: СЪЗДАЙ ИЗГЛЕД view_with_unionall КАТО (ИЗБЕРИ c.rowid crid, c.cust_id, 2 umarker ОТ клиенти c КЪДЕTO c.cust_last_name = 'Смит' UNION ALL ИЗБЕРИ c.rowid crid, c.cust_id, 3 umarker ОТ клиенти c КЪДЕTO c.cust_last_name = 'Джонс');СЪЗДАЙ МАТЕРИАЛИЗИРАН ИЗГЛЕД unionall_inside_view_mv БЪРЗО ОБНОВЯВАНЕ ПО ТЪРСЕНЕ КАТО ИЗБЕРИ * ОТ view_with_unionall; Обърнете внимание, че изгледът UNION ALLview_with_unionall

    отговаря на изискванията за бързо обновление.
    

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

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

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

  • The SELECT клон. Освен това, колоната с маркер трябва да се появява в същата редова позиция в UNION ALL списъка на всяко запитване. Вижте « UNION ALL UNION ALL Маркер и Пренаписване на Запитвания UNION ALL » за повече информация относно SELECT маркерите.Някои функции, като външни съединения, запитвания за агрегатни материализирани изгледи, които правят само вмъквания и отдалечени таблици, не се поддържат за материализирани изгледи с. Обърнете внимание обаче, че материализованите изгледи, използвани в репликация и които не съдържат съединения или агрегати, могат да бъдат бързо обновени, когато UNION ALL или се използват отдалечени таблици.
  • Параметърът за инициализация на съвместимостта трябва да бъде зададен на 9.2.0 или по-висок, за да създадете бързо обновяем материализиран изглед с UNION ALLОбаче, материализованите изгледи, използвани в репликация, които не съдържат обърквания или агрегати, могат да бъдат бързо обновявани, когато UNION ALL или се използват отдалечени таблици.
  • Параметърът на инициализацията за съвместимост трябва да бъде зададен на 9.2.0 или по-висок, за да създаде бързо обновяващ се материализиран изглед с UNION ALL.

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

Microsoft SQL Server

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

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

  • Потребителят, който изпълнява CREATE INDEX трябва да бъде собственик на изгледа.
  • Когато създавате индекса, опцията IGNORE_DUP_KEY трябва да бъде зададена на OFF (по подразбиране).
  • Таблиците трябва да бъдат посочени с двучастни имена, schema.tablename в дефиницията на изгледа.
  • Потребителските функции, на които се позовавате в изгледа, трябва да бъдат създадени с опцията WITH SCHEMABINDING. Всички потребителски функции, на които се позовавате в изгледа, трябва да бъдат посочени с двучастни имена,
  • Всяка потребителска функция, спомената в изгледа, трябва да бъде посочена с двучастни имена, <schema>.Достъпността на данни на потребителската функция трябва да бъде.
  • NO SQL , а свойството за външен достъп трябва да бъдеNO Функции за общ език на програмиране (CLR) могат да се появят в селект списъка на изгледа, но не могат да бъдат част от дефиницията на ключа на клъстерния индекс. CLR функции не могат да се появят в WHERE клаузата на изгледа или в ON клаузата на JOIN операция в изгледа..
  • CLR функции и методи на потребителски типове CLR, използвани в дефиницията на изгледа, трябва да имат свойствата зададени, както е показано в следната таблица.
  • DETERMINISTIC = TRUE

    Свойство
    Note

    Трябва да бъде декларирано изрично като атрибут на метода на 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:
  • ROWSET функции (

    COUNT
    OPENDATASOURCEOPENQUERY, OPENROWSET, , ИOPENXML EXTERNAL)
    съединения ( LEFTRIGHT, FULL, или Изведена таблица (определена чрез задаване на)

    изречение в SELECT клаузата) OT Самосъединения
    Посочване на колони, като се използва
    SELECT * SELECT

    .* или STDEV

    DISTINCT
    STDEVP, VAR, VARP, Обща таблица израз (CTE), или СРЕДНО
    text

    float1, ntext, filestream, изображение, XML, или колони Подзаявка
    OVER
    клауза, която включва функции за ранжиране или агрегатни прозоречни функции Предикати с пълен текст (

    CONTAINSFREETEXT, функция, която позовава на допускаща израз)
    СУМА ORDER BY
    CLR потребителска агрегатна функция

    TOP
    GROUPING SETS
    КУБ, РУЛООП, или оператори EXCEPT

    МИН, МАКС
    UNION, TABLESAMPLE, или INTERSECT EXCEPT
    Таблични променливи

    OUTER APPLY
    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:

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

    ROWSET функции (

    COUNT
    OPENDATASOURCEOPENQUERY, OPENROWSET, , ИOPENXML EXTERNAL)
    съединения ( LEFTRIGHT, FULL, или Изведена таблица (определена чрез задаване на)

    изречение в SELECT клаузата) OT Самосъединения
    Посочване на колони, като се използва
    SELECT * SELECT

    .* или STDEV

    DISTINCT
    STDEVP, VAR, VARP, Обща таблица израз (CTE), или СРЕДНО
    text

    float1, ntext, filestream, изображение, XML, или колони Подзаявка
    OVER
    клауза, която включва функции за ранжиране или агрегатни прозоречни функции Предикати с пълен текст (

    CONTAINSFREETEXT, функция, която позовава на допускаща израз)
    СУМА ORDER BY
    CLR потребителска агрегатна функция

    TOP
    GROUPING SETS
    КУБ, РУЛООП, или оператори EXCEPT

    МИН, МАКС
    UNION, TABLESAMPLE, или INTERSECT EXCEPT
    Таблични променливи

    OUTER APPLY
    CROSS APPLY или PIVOT
    UNPIVOT, Редки колонни сетове

    Инлайн (TVF) или многостепенни функции с таблица стойности (MSTVF)
    OFFSET
    CHECKSUM_AGG

    1 Индексираният изглед може да съдържа

    Забранени са OUTER JOINS, UNION, ORDER BY и други. Може би беше по-просто да се посочи какво е разрешено да се използва, отколкото какво е забранено. Списъкът вероятно щеше да е значително по-кратък.

    В заключение: огромен набор от ограничения във всяка (да отбележа търговска) СУБД срещу никакви (с изключение на един логически, а не технически) в LGPL технологията. Въпреки това, трябва да се отбележи, че реализирането на този механизъм в релационната логика е малко по-сложно, отколкото в описаната функционална.

    Реализация

    Как работи това? Като „виртуална машина“ се използва PostgreSQL. Вътре има сложен алгоритъм, който се занимава с построението на запитвания. Ето изходния код. И там не просто има голям набор от хевристики с много if’ове. Така че, ако имате два месеца за изучаване, можете да опитате да разберете архитектурата.

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

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

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

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