Równoważenie zapisuje i odczytuje w bazie danych

Równoważenie zapisuje i odczytuje w bazie danych
W poprzednim Artykuł Opisałem koncepcję i realizację bazy danych zbudowanej w oparciu o funkcje, a nie tabele i pola jak w relacyjnych bazach danych. Podaje wiele przykładów pokazujących przewagę tego podejścia nad klasycznym. Wielu uznało je za niewystarczająco przekonujące.

W tym artykule pokażę, jak koncepcja ta pozwala szybko i wygodnie zrównoważyć zapisy i odczyty do bazy danych bez zmiany logiki działania. Próbowano wdrożyć podobną funkcjonalność w nowoczesnych komercyjnych systemach DBMS (w szczególności w Oracle i Microsoft SQL Server). Na koniec artykułu wykażę, że to co zrobili, delikatnie mówiąc, nie wyszło zbyt dobrze.

Opis

Tak jak poprzednio, dla lepszego zrozumienia opis rozpocznę od przykładów. Załóżmy, że musimy wdrożyć logikę, która zwróci listę działów z liczbą zatrudnionych w nich pracowników i ich całkowitym wynagrodzeniem.

W funkcjonalnej bazie danych wyglądałoby to tak:

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

Złożoność wykonania tego zapytania w dowolnym systemie DBMS będzie równa O(liczba pracowników)ponieważ to obliczenie wymaga przeskanowania całej tabeli pracowników, a następnie pogrupowania ich według działów. Dodatek będzie też niewielki (uważamy, że pracowników jest znacznie więcej niż działów) w zależności od wybranego planu O (logowana liczba pracowników) lub O (liczba działów) do grupowania i tak dalej.

Oczywiste jest, że obciążenie wykonaniem może być różne w różnych systemach DBMS, ale złożoność nie ulegnie żadnej zmianie.

W proponowanej implementacji funkcjonalny DBMS wygeneruje jedno podzapytanie, które obliczy wymagane wartości dla działu, a następnie wykona JOIN z tabelą działu w celu uzyskania nazwy. Jednakże dla każdej funkcji przy deklaracji można ustawić specjalny znacznik MATERIALIZED. Dla każdej takiej funkcji system automatycznie utworzy odpowiednie pole. Zmieniając wartość funkcji, wartość pola również ulegnie zmianie w tej samej transakcji. Po uzyskaniu dostępu do tej funkcji uzyskany zostanie dostęp do wstępnie obliczonego pola.

W szczególności, jeśli ustawisz MATERIALIZED dla funkcji liczyć pracowników и wynagrodzenieSuma, wówczas do tabeli z listą działów zostaną dodane dwa pola, w których będzie przechowywana liczba pracowników i ich łączne wynagrodzenie. Ilekroć nastąpi zmiana pracowników, ich wynagrodzeń lub przynależności do działów, system automatycznie zmieni wartości tych pól. Powyższe zapytanie uzyska bezpośredni dostęp do tych pól i zostanie wykonane O (liczba działów).

Jakie są ograniczenia? Tylko jedno: taka funkcja musi mieć skończoną liczbę wartości wejściowych, dla których zdefiniowana jest jej wartość. W przeciwnym razie nie będzie możliwe zbudowanie tabeli przechowującej wszystkie jej wartości, ponieważ nie może istnieć tabela z nieskończoną liczbą wierszy.

Przykład:

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

Ta funkcja jest zdefiniowana dla nieskończonej liczby wartości N (na przykład odpowiednia jest dowolna wartość ujemna). Dlatego nie możesz na nim umieścić MATERIALIZED. Jest to więc ograniczenie logiczne, a nie techniczne (to znaczy nie dlatego, że nie mogliśmy go wdrożyć). W przeciwnym razie nie ma żadnych ograniczeń. Możesz używać grupowania, sortowania, AND i OR, PARTYCJI, rekurencji itp.

Na przykład w zadaniu 2.2 z poprzedniego artykułu możesz umieścić MATERIALIZED na obu funkcjach:

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;

Sam system utworzy jedną tabelę z kluczami typów Klient, Produkt и LICZBA CAŁKOWITA, doda do niego dwa pola i zaktualizuje znajdujące się w nich wartości pól wraz z ewentualnymi zmianami. W przypadku kolejnych wywołań tych funkcji nie zostaną one przeliczone, lecz odczytane zostaną wartości z odpowiednich pól.

Korzystając z tego mechanizmu można np. pozbyć się rekurencji (CTE) w zapytaniach. W szczególności rozważ grupy tworzące drzewo przy użyciu relacji dziecko/rodzic (każda grupa ma łącze do swojego rodzica):

parent = DATA Group (Group);

W funkcjonalnej bazie danych logikę rekurencji można określić w następujący sposób:

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;

Ponieważ dla funkcji jestRodzic jest oznaczony ZMATERIALIZOWANY, wówczas zostanie dla niego utworzona tabela z dwoma kluczami (grupami), w której pole jestRodzic będzie prawdziwe tylko wtedy, gdy pierwszy klucz jest dzieckiem drugiego. Liczba wpisów w tej tabeli będzie równa liczbie grup pomnożonej przez średnią głębokość drzewa. Jeśli potrzebujesz na przykład policzyć liczbę potomków określonej grupy, możesz skorzystać z tej funkcji:

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

W zapytaniu SQL nie będzie CTE. Zamiast tego będzie prosta GROUP BY.

Korzystając z tego mechanizmu, możesz także łatwo zdenormalizować bazę danych, jeśli zajdzie taka potrzeba:

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

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

Podczas wywoływania funkcji dane dla linii zamówienia pole, dla którego znajduje się indeks, zostanie odczytane z tabeli z liniami zamówienia. W przypadku zmiany daty zamówienia system sam automatycznie przeliczy w wierszu zdenormalizowaną datę.

Zalety

Do czego służy cały ten mechanizm? W klasycznych systemach DBMS, bez przepisywania zapytań, programista lub administrator bazy danych może jedynie zmieniać indeksy, ustalać statystyki i mówić planiście zapytań, jak je wykonać (a wskazówki są dostępne tylko w komercyjnych systemach DBMS). Bez względu na to, jak bardzo będą się starać, nie będą w stanie wykonać pierwszego zapytania z artykułu w O (liczba działów) bez zmiany zapytań i dodawania wyzwalaczy. W proponowanym schemacie na etapie rozwoju nie trzeba myśleć o strukturze przechowywania danych i jakich agregacjach zastosować. Wszystko to można łatwo zmienić w locie, bezpośrednio w działaniu.

W praktyce wygląda to tak. Niektórzy ludzie rozwijają logikę bezpośrednio w oparciu o wykonywane zadanie. Nie rozumieją algorytmów i ich złożoności, ani planów wykonania, ani typów złączeń, ani żadnego innego komponentu technicznego. Ci ludzie są bardziej analitykami biznesowymi niż programistami. Następnie wszystko to trafia do testów lub eksploatacji. Umożliwia rejestrowanie długotrwałych zapytań. Po wykryciu długiego zapytania inne osoby (bardziej techniczne - zasadniczo DBA) decydują się na włączenie MATERIALIZED w jakiejś funkcji pośredniej. Spowalnia to nieco rejestrację (ponieważ wymaga aktualizacji dodatkowego pola w transakcji). Jednak nie tylko to zapytanie zostaje znacznie przyspieszone, ale także wszystkie inne, które korzystają z tej funkcji. Jednocześnie podjęcie decyzji, która funkcja ma się zmaterializować, jest stosunkowo łatwe. Dwa główne parametry: liczba możliwych wartości wejściowych (tyle będzie rekordów w odpowiedniej tabeli) i częstotliwość ich używania w innych funkcjach.

Analogi

Nowoczesne komercyjne systemy DBMS mają podobne mechanizmy: WIDOK ZMATERIALIZOWANY z FAST REFRESH (Oracle) i WIDOK INDEKSOWANY (Microsoft SQL Server). W PostgreSQL MATERIALIZED VIEW nie może być aktualizowany w transakcji, a jedynie na żądanie (i nawet przy bardzo rygorystycznych ograniczeniach), więc nie bierzemy tego pod uwagę. Mają jednak kilka problemów, które znacznie ograniczają ich zastosowanie.

Po pierwsze, możesz włączyć materializację tylko wtedy, gdy utworzyłeś już zwykły WIDOK. W przeciwnym razie będziesz musiał przepisać pozostałe żądania, aby uzyskać dostęp do nowo utworzonego widoku i skorzystać z tej materializacji. Lub zostaw wszystko tak, jak jest, ale będzie to przynajmniej nieskuteczne, jeśli istnieją pewne wstępnie obliczone dane, ale wiele zapytań nie zawsze z nich korzysta, ale przelicza je.

Po drugie, mają ogromną liczbę ograniczeń:

wyrocznia

5.3.8.4 Ogólne ograniczenia dotyczące szybkiego odświeżania

Zapytanie definiujące pogląd zmaterializowany jest ograniczone w następujący sposób:

  • Zmaterializowany widok nie może zawierać odniesień do niepowtarzalnych wyrażeń, takich jak SYSDATE i ROWNUM.
  • Zmaterializowany widok nie może zawierać odniesień do RAW or LONG RAW typy danych.
  • Nie może zawierać a SELECT podzapytanie listowe.
  • Nie może zawierać funkcji analitycznych (np. RANK) w SELECT klauzula.
  • Nie może odwoływać się do tabeli, na której znajduje się plik an XMLIndex indeks jest zdefiniowany.
  • Nie może zawierać a MODEL klauzula.
  • Nie może zawierać a HAVING klauzula z podzapytaniem.
  • Nie może zawierać zagnieżdżonych zapytań, które mają ANY, ALLlub NOT EXISTS.
  • Nie może zawierać a [START WITH …] CONNECT BY klauzula.
  • Nie może zawierać wielu tabel szczegółowych w różnych witrynach.
  • ON COMMIT widoki zmaterializowane nie mogą zawierać zdalnych tabel szczegółów.
  • Zagnieżdżone widoki zmaterializowane muszą mieć połączenie lub agregację.
  • Zmaterializowane widoki połączeń i zmaterializowane widoki zagregowane za pomocą a GROUP BY klauzula nie może wybierać z tabeli zorganizowanej według indeksu.

5.3.8.5 Ograniczenia dotyczące szybkiego odświeżania widoków zmaterializowanych wyłącznie z połączeniami

Definiowanie zapytań dla widoków zmaterializowanych zawierających wyłącznie sprzężenia i bez agregatów ma następujące ograniczenia dotyczące szybkiego odświeżania:

  • Wszystkie ograniczenia od «Ogólne ograniczenia dotyczące szybkiego odświeżania".
  • Nie mogą mieć GROUP BY klauzule lub agregaty.
  • Wiersze wszystkich tabel w pliku FROM lista musi pojawić się w SELECT lista zapytania.
  • Dzienniki widoku zmaterializowanego muszą istnieć z identyfikatorami wierszy dla wszystkich tabel podstawowych w pliku FROM lista zapytania.
  • Nie można utworzyć szybko odświeżalnego widoku zmaterializowanego z wielu tabel za pomocą prostych złączeń zawierających kolumnę typu obiektu w pliku SELECT komunikat.

Ponadto wybrana metoda odświeżania nie będzie optymalnie wydajna, jeśli:

  • Zapytanie definiujące używa sprzężenia zewnętrznego, które zachowuje się jak sprzężenie wewnętrzne. Jeśli zapytanie definiujące zawiera takie złączenie, rozważ przepisanie zapytania definiującego tak, aby zawierało złączenie wewnętrzne.
  • Połączenia SELECT lista zmaterializowanego widoku zawiera wyrażenia w kolumnach z wielu tabel.

5.3.8.6 Ograniczenia dotyczące szybkiego odświeżania widoków zmaterializowanych z agregatami

Definiowanie zapytań dla widoków zmaterializowanych z agregacjami lub złączeniami ma następujące ograniczenia dotyczące szybkiego odświeżania:

W obu przypadkach obsługiwane jest szybkie odświeżanie ON COMMIT i ON DEMAND zmaterializowane poglądy, jednakże obowiązują następujące ograniczenia:

  • Wszystkie tabele w widoku zmaterializowanym muszą mieć dzienniki widoku zmaterializowanego, a dzienniki widoku zmaterializowanego muszą:
    • Zawiera wszystkie kolumny z tabeli, do których odwołują się widoki zmaterializowane.
    • Określ za pomocą ROWID i INCLUDING NEW VALUES.
    • Określ SEQUENCE klauzula, jeśli oczekuje się, że tabela będzie zawierała kombinację wstawień/bezpośrednich ładowań, usunięć i aktualizacji.

  • Only SUM, COUNT, AVG, STDDEV, VARIANCE, MIN i MAX są obsługiwane w celu szybkiego odświeżania.
  • COUNT(*) należy określić.
  • Funkcje agregujące muszą występować tylko jako najbardziej zewnętrzna część wyrażenia. Czyli agregaty takie jak AVG(AVG(x)) or AVG(x)+ AVG(x) niedozwolone.
  • Dla każdego agregatu np AVG(expr), odpowiadający COUNT(expr) musi być obecny. Oracle to zaleca SUM(expr) być określony.
  • If VARIANCE(expr) or STDDEV(expr) jest specyficzne, COUNT(expr) i SUM(expr) należy określić. Oracle to zaleca SUM(expr *expr) być określony.
  • Połączenia SELECT kolumna w zapytaniu definiującym nie może być wyrażeniem złożonym zawierającym kolumny z wielu tabel podstawowych. Możliwym obejściem tego problemu jest użycie zagnieżdżonego widoku zmaterializowanego.
  • Połączenia SELECT lista musi zawierać wszystko GROUP BY kolumny.
  • Zmaterializowany widok nie opiera się na jednej lub większej liczbie zdalnych tabel.
  • Jeśli używasz CHAR typ danych w kolumnach filtra dziennika widoku zmaterializowanego, zestawy znaków witryny głównej i widoku zmaterializowanego muszą być takie same.
  • Jeśli zmaterializowany widok ma jedną z poniższych cech, szybkie odświeżanie jest obsługiwane tylko w przypadku konwencjonalnych wstawek DML i ładunków bezpośrednich.
    • Zmaterializowane poglądy z MIN or MAX agregaty
    • Zmaterializowane poglądy, które mają SUM(expr) ale nie COUNT(expr)
    • Zmaterializowane poglądy bez COUNT(*)

    Taki zmaterializowany widok nazywany jest zmaterializowanym widokiem zawierającym tylko wstawki.

  • Zmaterializowany pogląd MAX or MIN można szybko odświeżyć po usunięciu lub zmieszaniu instrukcji DML, jeśli nie ma WHERE klauzula.
    Szybkie odświeżanie max/min po usunięciu lub mieszanym DML nie ma takiego samego zachowania jak przypadek tylko wstawiania. Usuwa i ponownie oblicza wartości maksymalne/min dla grup, których to dotyczy. Musisz zdawać sobie sprawę z jego wpływu na wydajność.
  • Zmaterializowane widoki z nazwanymi widokami lub podzapytaniami w FROM klauzulę można szybko odświeżyć, pod warunkiem, że widoki można całkowicie scalić. Aby uzyskać informacje o tym, które widoki zostaną scalone, zobacz Dokumentacja języka SQL bazy danych Oracle.
  • Jeśli nie ma żadnych złączeń zewnętrznych, możesz mieć dowolne selekcje i połączenia w pliku WHERE klauzula.
  • Zmaterializowane widoki zagregowane ze sprzężeniami zewnętrznymi można szybko odświeżać po konwencjonalnym DML i ładowaniu bezpośrednim, pod warunkiem, że zmodyfikowana została tylko tabela zewnętrzna. Ponadto w kolumnach łączenia wewnętrznej tabeli łączenia muszą istnieć unikalne ograniczenia. Jeśli istnieją połączenia zewnętrzne, wszystkie połączenia muszą być połączone za pomocą ANDs i musi użyć równości (=) operatora.
  • Dla zmaterializowanych poglądów z CUBE, ROLLUP, grupowanie zbiorów lub ich łączenie, obowiązują następujące ograniczenia:
    • Połączenia SELECT lista powinna zawierać wyróżnik grupowania, którym może być a GROUPING_ID działać na wszystkich GROUP BY wyrażenia lub GROUPING funkcje po jednej dla każdego GROUP BY wyrażenie. Na przykład, jeśli GROUP BY klauzula zmaterializowanego poglądu brzmi: „GROUP BY CUBE(a, b)", a później SELECT lista powinna zawierać albo „GROUPING_ID(a, b)" lub "GROUPING(a) AND GROUPING(b)» aby zmaterializowany widok był szybko odświeżalny.
    • GROUP BY nie powinno powodować duplikacji grupowania. Na przykład, "GROUP BY a, ROLLUP(a, b)„nie można go szybko odświeżyć, ponieważ powoduje to zduplikowane grupowanie”(a), (a, b), AND (a)".

5.3.8.7 Ograniczenia szybkiego odświeżania widoków zmaterializowanych w UNION ALL

Zmaterializowane poglądy z UNION ALL zestaw obsługuje operatora REFRESH FAST opcja, jeśli spełnione są następujące warunki:

  • Zapytanie definiujące musi mieć UNION ALL operator na najwyższym poziomie.

    Połączenia UNION ALL operatora nie można osadzić w podzapytaniu, z jednym wyjątkiem: The UNION ALL może znajdować się w podzapytaniu w FROM klauzula pod warunkiem, że zapytanie definiujące ma postać SELECT * FROM (widok lub podzapytanie za pomocą UNION ALL) jak w poniższym przykładzie:

    UTWÓRZ WIDOK view_with_unionall AS (WYBIERZ c.rowid crid, c.cust_id, 2 umarker OD klientów c WHERE c.cust_last_name = 'Smith' UNION WSZYSTKO WYBIERZ c.rowid crid, c.cust_id, 3 umarker OD klientów c WHERE c.cust_last_name = „Jones”); UTWÓRZ ZMATERIALIZOWANY WIDOK unionall_inside_view_mv ODŚWIEŻ SZYBKO NA ŻĄDANIE JAKO WYBIERZ * Z view_with_unionall;
    

    Należy pamiętać, że widok view_with_unionall spełnia wymagania szybkiego odświeżania.

  • Każdy blok zapytań w UNION ALL zapytanie musi spełniać wymagania szybko odświeżalnego widoku zmaterializowanego z agregatami lub szybko odświeżalnego widoku zmaterializowanego ze złączeniami.

    W tabelach należy utworzyć odpowiednie dzienniki widoku zmaterializowanego, zgodnie z wymaganiami dla odpowiedniego typu widoku zmaterializowanego, który można szybko odświeżać.
    Należy pamiętać, że baza danych Oracle dopuszcza również specjalny przypadek zmaterializowanego widoku pojedynczej tabeli z połączeniami tylko pod warunkiem ROWID kolumna została uwzględniona w SELECT liście oraz w dzienniku widoku zmaterializowanego. Jest to pokazane w zapytaniu definiującym widok view_with_unionall.

  • Połączenia SELECT lista każdego zapytania musi zawierać a UNION ALL znacznik i UNION ALL każda kolumna musi mieć odrębną stałą wartość liczbową lub łańcuchową UNION ALL oddział. Co więcej, kolumna znacznika musi znajdować się w tej samej pozycji porządkowej w SELECT lista każdego bloku zapytań. Widzieć "UNION ALL Marker i przepisanie zapytania» więcej informacji dot UNION ALL markery.
  • Niektóre funkcje, takie jak łączenia zewnętrzne, zapytania dotyczące zagregowanych widoków zmaterializowanych umożliwiające tylko wstawianie i tabele zdalne, nie są obsługiwane w przypadku widoków zmaterializowanych z UNION ALL. Należy jednak pamiętać, że zmaterializowane widoki używane w replikacji, które nie zawierają złączeń ani agregacji, można szybko odświeżyć, gdy UNION ALL lub używane są tabele zdalne.
  • Parametr inicjalizacji zgodności musi być ustawiony na 9.2.0 lub nowszy, aby utworzyć szybko odświeżalny widok zmaterializowany UNION ALL.

Nie chcę urazić fanów Oracle, ale sądząc po ich liście ograniczeń, wydaje się, że mechanizm ten nie został napisany w ogólnym przypadku, na podstawie jakiegoś modelu, ale przez tysiące Hindusów, gdzie każdy miał możliwość napisz swój własny oddział i każdy z nich zrobił, co mógł. i zrobił. Używanie tego mechanizmu dla prawdziwej logiki jest jak chodzenie po polu minowym. Minę możesz zdobyć w dowolnym momencie, trafiając w jedno z nieoczywistych ograniczeń. Jak to działa, to także osobne pytanie, ale wykracza poza zakres tego artykułu.

Microsoft SQL Server

Dodatkowe wymagania

Oprócz opcji SET i wymagań dotyczących funkcji deterministycznych muszą zostać spełnione następujące wymagania:

  • Użytkownik, który wykonuje CREATE INDEX musi być właścicielem widoku.
  • Kiedy tworzysz indeks, plik IGNORE_DUP_KEY opcja musi być wyłączona (ustawienie domyślne).
  • Do tabel należy odwoływać się za pomocą nazw dwuczęściowych, schemat.Nazwa tabeli w definicji widoku.
  • Funkcje zdefiniowane przez użytkownika, do których odwołuje się widok, należy utworzyć przy użyciu metody WITH SCHEMABINDING opcja.
  • Wszelkie funkcje zdefiniowane przez użytkownika, do których odwołują się w widoku, muszą zawierać dwuczęściowe nazwy, ..
  • Właściwość dostępu do danych funkcji zdefiniowanej przez użytkownika musi mieć postać NO SQL, a właściwość dostępu zewnętrznego musi być NO.
  • Funkcje środowiska uruchomieniowego języka wspólnego (CLR) mogą pojawiać się na liście wyboru widoku, ale nie mogą być częścią definicji klucza indeksu klastrowego. Funkcje CLR nie mogą pojawiać się w klauzuli WHERE widoku ani w klauzuli ON operacji JOIN w widoku.
  • Funkcje i metody CLR typów zdefiniowanych przez użytkownika CLR używane w definicji widoku muszą mieć ustawione właściwości, jak pokazano w poniższej tabeli.

    Nieruchomość
    Note

    DETERMINISTYCZNY = PRAWDA
    Należy jawnie zadeklarować jako atrybut metody Microsoft .NET Framework.

    PRECYZYJNE = PRAWDZIWE
    Musi być zadeklarowany jawnie jako atrybut metody .NET Framework.

    DOSTĘP DO DANYCH = BRAK SQL
    Określane przez ustawienie atrybutu DataAccess na DataAccessKind.None i atrybutu SystemDataAccess na SystemDataAccessKind.None.

    DOSTĘP ZEWNĘTRZNY = NIE
    Ta właściwość ma wartość domyślną NIE dla procedur CLR.

  • Widok musi zostać utworzony przy użyciu metody WITH SCHEMABINDING opcja.
  • Widok musi odwoływać się tylko do tabel podstawowych, które znajdują się w tej samej bazie danych co widok. Widok nie może odwoływać się do innych widoków.
  • Instrukcja SELECT w definicji widoku nie może zawierać następujących elementów języka Transact-SQL:

    COUNT
    Funkcje ZESTAWU WIERSZA (OPENDATASOURCE, OPENQUERY, OPENROWSET, I OPENXML)
    OUTER dołącza (LEFT, RIGHTlub FULL)

    Tabela pochodna (zdefiniowana przez określenie a SELECT oświadczenie w FROM klauzula)
    Samozłącza
    Określanie kolumn za pomocą SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARPlub AVG
    Wspólne wyrażenie tabelowe (CTE)

    unosić się1, XNUMX, ntekst, obraz, XMLlub strumień plików kolumny
    Podzapytanie
    OVER klauzula, która zawiera funkcje okna rankingowego lub agregującego

    Predykaty pełnotekstowe (CONTAINS, FREETEXT)
    SUM funkcja, która odwołuje się do wyrażenia dopuszczającego wartość null
    ORDER BY

    Funkcja agregująca zdefiniowana przez użytkownika CLR
    TOP
    CUBE, ROLLUPlub GROUPING SETS operatorzy

    MIN, MAX
    UNION, EXCEPTlub INTERSECT operatorzy
    TABLESAMPLE

    Zmienne tabeli
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Rzadkie zestawy kolumn
    Funkcje wbudowane (TVF) lub wieloinstrukcyjne funkcje z wartościami przechowywanymi w tabeli (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 Widok indeksowany może zawierać unosić się kolumny; jednakże takich kolumn nie można uwzględnić w kluczu indeksu klastrowego.

  • If GROUP BY jest obecny, definicja WIDOKU musi zawierać COUNT_BIG(*) i nie może zawierać HAVING, Te GROUP BY ograniczenia mają zastosowanie tylko do definicji widoku indeksowanego. Zapytanie może używać widoku indeksowanego w swoim planie wykonania, nawet jeśli ich nie spełnia GROUP BY ograniczenia.
  • Jeśli definicja widoku zawiera a GROUP BY klauzuli klucz unikalnego indeksu klastrowego może odwoływać się tylko do kolumn określonych w GROUP BY klauzula.

Widać tutaj wyraźnie, że Hindusi nie byli w to zaangażowani, ponieważ postanowili to zrobić według schematu „zrobimy niewiele, ale dobrze”. Oznacza to, że mają więcej min na polu, ale ich lokalizacja jest bardziej przejrzysta. Najbardziej rozczarowujące jest to ograniczenie:

Widok musi odwoływać się tylko do tabel podstawowych, które znajdują się w tej samej bazie danych co widok. Widok nie może odwoływać się do innych widoków.

W naszej terminologii oznacza to, że funkcja nie może uzyskać dostępu do innej zmaterializowanej funkcji. To eliminuje wszelką ideologię w zarodku.
Ponadto to ograniczenie (i dalsza część tekstu) znacznie ogranicza przypadki użycia:

Instrukcja SELECT w definicji widoku nie może zawierać następujących elementów języka Transact-SQL:

COUNT
Funkcje ZESTAWU WIERSZA (OPENDATASOURCE, OPENQUERY, OPENROWSET, I OPENXML)
OUTER dołącza (LEFT, RIGHTlub FULL)

Tabela pochodna (zdefiniowana przez określenie a SELECT oświadczenie w FROM klauzula)
Samozłącza
Określanie kolumn za pomocą SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARPlub AVG
Wspólne wyrażenie tabelowe (CTE)

unosić się1, XNUMX, ntekst, obraz, XMLlub strumień plików kolumny
Podzapytanie
OVER klauzula, która zawiera funkcje okna rankingowego lub agregującego

Predykaty pełnotekstowe (CONTAINS, FREETEXT)
SUM funkcja, która odwołuje się do wyrażenia dopuszczającego wartość null
ORDER BY

Funkcja agregująca zdefiniowana przez użytkownika CLR
TOP
CUBE, ROLLUPlub GROUPING SETS operatorzy

MIN, MAX
UNION, EXCEPTlub INTERSECT operatorzy
TABLESAMPLE

Zmienne tabeli
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Rzadkie zestawy kolumn
Funkcje wbudowane (TVF) lub wieloinstrukcyjne funkcje z wartościami przechowywanymi w tabeli (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY i inne są zabronione. Być może łatwiej byłoby określić, czego można użyć, niż tego, czego nie można użyć. Lista prawdopodobnie byłaby znacznie krótsza.

Podsumowując: ogromny zestaw ograniczeń w każdym (powiedzmy komercyjnym) DBMS vs brak (z wyjątkiem jednego logicznego, a nie technicznego) w technologii LGPL. Należy jednak zaznaczyć, że implementacja tego mechanizmu w logice relacyjnej jest nieco trudniejsza niż w opisywanej logice funkcjonalnej.

realizacja

Jak to działa? PostgreSQL jest używany jako „maszyna wirtualna”. Wewnątrz znajduje się złożony algorytm budujący zapytania. Tutaj źródło. I nie ma tu tylko dużego zestawu heurystyk z mnóstwem ifów. Jeśli więc masz kilka miesięcy na naukę, możesz spróbować zrozumieć architekturę.

Czy to działa skutecznie? Całkiem skuteczny. Niestety, ciężko to udowodnić. Mogę tylko powiedzieć, że jeśli weźmie się pod uwagę tysiące zapytań występujących w dużych aplikacjach, to przeciętnie są one bardziej wydajne niż zapytania dobrego programisty. Doskonały programista SQL potrafi sprawniej napisać każde zapytanie, ale przy tysiącu zapytań po prostu nie będzie miał na to motywacji ani czasu. Jedyne co mogę teraz przytoczyć jako dowód skuteczności to to, że na platformie zbudowanej na tym DBMS pracuje kilka projektów Systemy ERP, które mają tysiące różnych ZMATERIALIZOWANYCH funkcji, z tysiącami użytkowników i terabajtowymi bazami danych z setkami milionów rekordów działającymi na zwykłym dwuprocesorowym serwerze. Jednak każdy może sprawdzić/zaprzeczyć skuteczności, pobierając platforma i PostgreSQL-a, włączanie rejestrowanie zapytań SQL i próba zmiany tam logiki i danych.

W kolejnych artykułach opowiem również o tym, jak ustawić ograniczenia funkcji, pracować z sesjami zmian i wiele więcej.

Źródło: www.habr.com

Dodaj komentarz