Datenbank-Schreib- und Leseausgleich

Bild

In einem früheren Artikel habe ich das Konzept und die Implementierung einer Datenbank beschrieben, die auf Funktionen basiert und nicht auf Tabellen und Feldern wie in relationalen Datenbanken. Es gab viele Beispiele, die die Vorteile dieses Ansatzes gegenüber dem Klassiker zeigten. Viele fanden sie nicht überzeugend genug.

In diesem Artikel werde ich zeigen, wie Sie mit diesem Konzept das Schreiben und Lesen in der Datenbank schnell und bequem ausgleichen können, ohne die Arbeitslogik zu ändern. Sie versuchten, ähnliche Funktionen in modernen kommerziellen DBMS (insbesondere Oracle und Microsoft SQL Server) zu implementieren. Am Ende des Artikels werde ich zeigen, was mit ihnen passiert ist, um es milde auszudrücken, nicht sehr.

Beschreibung


Zum besseren Verständnis beginne ich die Beschreibung nach wie vor mit Beispielen. Angenommen, wir müssen eine Logik implementieren, die eine Liste der Abteilungen mit der Anzahl der Mitarbeiter und ihrem Gesamtgehalt zurückgibt.

In einer funktionalen Datenbank sieht es folgendermaßen aus:
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);
Die Komplexität der Ausführung dieser Abfrage in einem DBMS entspricht O (Anzahl der Mitarbeiter) , da Sie für diese Berechnung die gesamte Tabelle der Mitarbeiter scannen und sie dann nach Abteilungen gruppieren müssen. Abhängig vom gewählten Plan O (Protokollanzahl der Mitarbeiter) oder O (Anzahl der Abteilungen) für die Gruppierung usw. wird es auch einige kleine (wir glauben, dass es viel mehr Mitarbeiter als Abteilungen gibt) Ergänzungen geben.

Es ist klar, dass der Aufwand für die Ausführung in verschiedenen DBMS unterschiedlich sein kann, aber die Komplexität wird sich in keiner Weise ändern.

In der vorgeschlagenen Implementierung bildet das funktionale DBMS eine Unterabfrage, die die erforderlichen Werte für die Abteilung berechnet und dann eine Verknüpfung mit der Abteilungstabelle erstellt, um den Namen zu erhalten. Bei der Deklaration kann jedoch für jede Funktion ein spezieller MATERIALISIERTER Marker angegeben werden. Das System erstellt automatisch ein geeignetes Feld für jede dieser Funktionen. Wenn sich ein Funktionswert ändert, ändert sich der Feldwert in derselben Transaktion. Beim Zugriff auf diese Funktion wird bereits ein Rechtsbehelf gegen das berechnete Feld eingelegt.

Insbesondere wenn Sie MATERIALISIERT für die Funktionen countEmployees und SalarySum eingeben , werden in der Tabelle mit der Liste der Abteilungen zwei Felder hinzugefügt, in denen die Anzahl der Mitarbeiter und ihr Gesamtgehalt gespeichert werden. Bei jeder Änderung der Mitarbeiter, ihrer Gehälter oder der Zugehörigkeit zu Abteilungen ändert das System automatisch die Werte dieser Felder. Die obige Abfrage beginnt direkt mit dem Zugriff auf diese Felder und wird für O (Anzahl der Abteilungen) ausgeführt .

Was sind die Einschränkungen? Nur eines: Eine solche Funktion muss eine endliche Anzahl von Eingabewerten haben, für die ihr Wert definiert ist. Andernfalls ist es unmöglich, eine Tabelle zu erstellen, in der alle Werte gespeichert sind, da es keine Tabelle mit einer unendlichen Anzahl von Zeilen geben kann.

Ein Beispiel:
employeesCount ' > N' (Department d, NUMERIC [ 10 , 2 ] N) =
GROUP SUM salary(Employee e) IF department(e) = d AND salary(e) > N;
Diese Funktion ist für eine unendliche Anzahl von Werten der Zahl N definiert (zum Beispiel ist jeder negative Wert geeignet). Daher kann es nicht MATERIALISIERT werden. Dies ist also eine logische und keine technische Einschränkung (dh nicht, weil wir dies nicht implementieren konnten). Ansonsten keine Einschränkungen. Sie können Gruppierung, Sortierung, UND und ODER, PARTITION, Rekursion usw. verwenden.

In Aufgabe 2.2 des vorherigen Artikels können Sie beispielsweise MATERIALISIERT für beide Funktionen festlegen:
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 ;
Das System selbst erstellt eine Tabelle mit Schlüsseln der Typen Customer , Product und INTEGER , fügt zwei Felder hinzu und aktualisiert die darin enthaltenen Feldwerte bei Änderungen. Bei weiteren Aufrufen dieser Funktionen werden diese nicht berechnet, sondern Werte aus den entsprechenden Feldern gelesen.

Mit diesem Mechanismus können Sie beispielsweise die Rekursion (CTE) in Abfragen entfernen. Berücksichtigen Sie insbesondere die Gruppen, aus denen der Baum besteht, unter Verwendung der Kind / Eltern-Beziehung (jede Gruppe hat einen Link zu ihrem Elternteil):
parent = DATA Group (Group);
In einer funktionalen Datenbank kann die Rekursionslogik wie folgt definiert werden:
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 ;
Da MATERIALIZED für die Funktion isParent angehängt ist, wird für sie eine Tabelle mit zwei Schlüsseln (Gruppen) erstellt, in der das Feld isParent nur dann wahr ist, wenn der erste Schlüssel ein Nachkomme des zweiten Schlüssels ist. Die Anzahl der Einträge in dieser Tabelle entspricht der Anzahl der Gruppen multipliziert mit der durchschnittlichen Tiefe des Baums. Wenn beispielsweise die Anzahl der Nachkommen einer bestimmten Gruppe berechnet werden muss, können Sie auf diese Funktion zugreifen:
childrenCount (Group g) = GROUP SUM 1 IF isParent(Group child, g);
Die SQL-Abfrage enthält keinen CTE. Stattdessen wird es eine einfache GROUP BY geben.

Mit diesem Mechanismus können Sie die Datenbank bei Bedarf auch problemlos denormalisieren:
CLASS Order '' ;
date '' = DATA DATE (Order);

CLASS OrderDetail ' ' ;
order '' = DATA Order (OrderDetail);
date '' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED ;
Wenn Sie die Datumsfunktion für die Bestellposition aufrufen, erfolgt das Lesen aus der Tabelle mit den Bestellpositionen des Felds, für das es einen Index gibt. Beim Ändern des Bestelldatums berechnet das System selbst das denormalisierte Datum in der Zeile automatisch neu.

Die Vorteile


Warum wird dieser ganze Mechanismus benötigt? In klassischen DBMS kann ein Entwickler oder DBA ohne Umschreiben von Abfragen nur Indizes ändern, Statistiken ermitteln und dem Abfrageplaner mitteilen, wie sie ausgeführt werden sollen (außerdem sind HINTs nur in kommerziellen DBMS verfügbar). Unabhängig davon, wie sehr sie sich bemühen, können sie die erste Anforderung im Artikel für O (Anzahl der Abteilungen) nicht erfüllen, ohne die Anforderungen zu ändern und Auslöser hinzuzufügen. In dem vorgeschlagenen Schema müssen Sie in der Entwicklungsphase nicht über die Struktur der Datenspeicherung und die zu verwendenden Aggregationen nachdenken. All dies kann einfach im laufenden Betrieb direkt im Betrieb geändert werden.

In der Praxis ist dies wie folgt. Einige Leute entwickeln Logik direkt basierend auf der Aufgabe. Sie kennen sich weder mit Algorithmen und ihrer Komplexität noch mit Ausführungsplänen, mit Join'ov-Typen oder mit anderen technischen Komponenten aus. Diese Leute sind mehr Geschäftsanalysten als Entwickler. Dann geht alles in den Test oder Betrieb. Die Protokollierung langer Abfragen ist aktiviert. Wenn eine lange Anforderung erkannt wird, entscheiden sich andere Personen (eher technisch - tatsächlich DBA) dafür, MATERIALISIERT in eine Zwischenfunktion aufzunehmen. Dadurch wird die Aufzeichnung etwas verlangsamt (da ein zusätzliches Feld in einer Transaktion aktualisiert werden muss). Dies wird jedoch nicht nur erheblich beschleunigt, sondern auch alle anderen, die diese Funktion verwenden. Gleichzeitig ist es relativ einfach, eine Entscheidung darüber zu treffen, welche bestimmte Funktion verwirklicht werden soll. Zwei Hauptparameter: Die Anzahl der möglichen Eingabewerte (genau wie viele Datensätze in der entsprechenden Tabelle enthalten sind) und wie oft sie in anderen Funktionen verwendet werden.

Analoga


Moderne kommerzielle DBMS verfügen über ähnliche Mechanismen: MATERIALISIERTE ANSICHT mit FAST REFRESH (Oracle) und INDEXED VIEW (Microsoft SQL Server). In PostgreSQL kann MATERIALIZED VIEW nicht in einer Transaktion aktualisiert werden, sondern nur auf Anfrage (und sogar mit sehr strengen Einschränkungen), daher berücksichtigen wir dies nicht. Sie haben jedoch mehrere Probleme, die ihre Verwendung stark einschränken.

Erstens können Sie die Materialisierung nur aktivieren, wenn Sie bereits eine reguläre ANSICHT erstellt haben. Andernfalls müssen Sie die verbleibenden Anforderungen für den Zugriff auf die neu erstellte Ansicht neu schreiben, um diese Materialisierung verwenden zu können. Oder lassen Sie alles so, wie es ist, aber es ist zumindest unwirksam, wenn bestimmte Daten bereits berechnet wurden, aber viele Abfragen verwenden sie nicht immer, sondern berechnen sie erneut.

Zweitens haben sie eine Vielzahl von Einschränkungen:

Oracle
5.3.8.4 Allgemeine Einschränkungen für die schnelle Aktualisierung

Die definierende Abfrage der materialisierten Ansicht ist wie folgt eingeschränkt:
  • Die materialisierte Ansicht darf keine Verweise auf sich nicht wiederholende Ausdrücke wie SYSDATE und ROWNUM .
  • Die materialisierte Ansicht darf keine Verweise auf RAW oder LONG RAW -Datentypen enthalten.
  • Es darf keine SELECT Listenunterabfrage enthalten.
  • Die SELECT Klausel darf keine Analysefunktionen (z. B. RANK ) enthalten.
  • Es kann nicht auf eine Tabelle verweisen, für die ein XMLIndex Index definiert ist.
  • Es darf keine MODEL Klausel enthalten.
  • Es darf keine HAVING Klausel mit einer Unterabfrage enthalten.
  • Es darf keine verschachtelten Abfragen enthalten, die ANY , ALL oder NOT EXISTS .
  • Es darf keine [START WITH …] CONNECT BY Klausel [START WITH …] CONNECT BY enthalten.
  • Es kann nicht mehrere Detailtabellen an verschiedenen Standorten enthalten.
  • ON COMMIT materialisierte Ansichten können keine Remote-Detailtabellen enthalten.
  • Verschachtelte materialisierte Ansichten müssen einen Join oder ein Aggregat haben.
  • Materialisierte Join-Ansichten und materialisierte Aggregatansichten mit einer GROUP BY Klausel können nicht aus einer indexorganisierten Tabelle ausgewählt werden.

5.3.8.5 Einschränkungen bei der schnellen Aktualisierung von materialisierten Ansichten nur mit Verknüpfungen

Das Definieren von Abfragen für materialisierte Ansichten nur mit Verknüpfungen und ohne Aggregate unterliegt den folgenden Einschränkungen für die schnelle Aktualisierung:
  • Alle Einschränkungen aus " Allgemeine Einschränkungen für die schnelle Aktualisierung ".
  • Sie dürfen keine GROUP BY Klauseln oder -Aggregate haben.
  • Rowids aller Tabellen in der FROM Liste müssen in der SELECT Liste der Abfrage angezeigt werden.
  • Materialisierte Ansichtsprotokolle müssen mit Zeilen-IDs für alle Basistabellen in der FROM Liste der Abfrage vorhanden sein.
  • Sie können keine schnell aktualisierbare materialisierte Ansicht aus mehreren Tabellen mit einfachen Verknüpfungen erstellen, die eine Objekttypspalte in der SELECT Anweisung enthalten.

Außerdem ist die von Ihnen gewählte Aktualisierungsmethode nicht optimal, wenn:
  • Die definierende Abfrage verwendet einen äußeren Join, der sich wie ein innerer Join verhält. Wenn die definierende Abfrage einen solchen Join enthält, sollten Sie die definierende Abfrage so umschreiben, dass sie einen inneren Join enthält.
  • Die SELECT Liste der materialisierten Ansicht enthält Ausdrücke für Spalten aus mehreren Tabellen.

5.3.8.6 Einschränkungen bei der schnellen Aktualisierung materialisierter Ansichten mit Aggregaten

Das Definieren von Abfragen für materialisierte Ansichten mit Aggregaten oder Verknüpfungen unterliegt den folgenden Einschränkungen für die schnelle Aktualisierung:

Die schnelle Aktualisierung wird sowohl für materialisierte ON COMMIT als auch für ON DEMAND Ansichten unterstützt. Es gelten jedoch die folgenden Einschränkungen:
  • Alle Tabellen in der materialisierten Ansicht müssen materialisierte Ansichtsprotokolle haben, und die materialisierten Ansichtsprotokolle müssen:
    • Enthalten alle Spalten aus der Tabelle, auf die in der materialisierten Ansicht verwiesen wird.
    • ROWID INCLUDING mit ROWID und INCLUDING VALUES .
    • Geben Sie die SEQUENCE Klausel an, wenn für die Tabelle eine Mischung aus Einfügungen / direkten Ladevorgängen, Löschvorgängen und Aktualisierungen erwartet wird.

  • Für eine schnelle Aktualisierung werden nur SUM , COUNT , AVG , VARIANCE , VARIANCE , MIN und MAX unterstützt.
  • COUNT(*) muss angegeben werden.
  • Aggregatfunktionen dürfen nur als äußerster Teil des Ausdrucks auftreten. Das heißt, Aggregate wie AVG(AVG(x)) oder AVG(x) + AVG(x) sind nicht zulässig.
  • Für jedes Aggregat wie AVG(expr) muss der entsprechende COUNT(expr) vorhanden sein. Oracle empfiehlt die SUM(expr) .
  • Wenn VARIANCE(expr) oder STDDEV(expr ) angegeben ist, müssen COUNT(expr) und SUM(expr) angegeben werden. Oracle empfiehlt die SUM(expr *expr) .
  • Die SELECT Spalte in der definierenden Abfrage kann kein komplexer Ausdruck mit Spalten aus mehreren Basistabellen sein. Eine mögliche Problemumgehung besteht darin, eine verschachtelte materialisierte Ansicht zu verwenden.
  • Die SELECT Liste muss alle GROUP BY Spalten enthalten.
  • Die materialisierte Ansicht basiert nicht auf einer oder mehreren entfernten Tabellen.
  • Wenn Sie in den Filterspalten eines materialisierten Ansichtsprotokolls einen CHAR Datentyp verwenden, müssen die Zeichensätze der Master-Site und der materialisierten Ansicht identisch sein.
  • Wenn die materialisierte Ansicht eine der folgenden Optionen aufweist, wird die schnelle Aktualisierung nur bei herkömmlichen DML-Einfügungen und direkten Lasten unterstützt.
    • Materialisierte Ansichten mit MIN oder MAX Aggregaten
    • Materialisierte Ansichten, die SUM(expr) aber keinen COUNT(expr)
    • Materialisierte Ansichten ohne COUNT(*)

    Eine solche materialisierte Ansicht wird als materialisierte Ansicht nur zum Einfügen bezeichnet.
  • Eine materialisierte Ansicht mit MAX oder MIN kann nach Lösch- oder gemischten DML-Anweisungen schnell aktualisiert werden, wenn sie keine WHERE Klausel enthält.
    Die maximale Aktualisierung von max / min nach dem Löschen oder der gemischten DML hat nicht das gleiche Verhalten wie der Nur-Einfügen-Fall. Es löscht und berechnet die Max / Min-Werte für die betroffenen Gruppen neu. Sie müssen sich der Auswirkungen auf die Leistung bewusst sein.
  • Materialisierte Ansichten mit benannten Ansichten oder Unterabfragen in der FROM Klausel können schnell aktualisiert werden, sofern die Ansichten vollständig zusammengeführt werden können. Informationen dazu, welche Ansichten zusammengeführt werden, finden Sie in der Oracle Database SQL-Sprachreferenz .
  • Wenn keine äußeren Verknüpfungen vorhanden sind, haben Sie möglicherweise eine beliebige Auswahl und Verknüpfungen in der WHERE Klausel.
  • Materialisierte Aggregatansichten mit äußeren Verknüpfungen können nach herkömmlicher DML und direktem Laden schnell aktualisiert werden, sofern nur die äußere Tabelle geändert wurde. Außerdem müssen eindeutige Einschränkungen für die Verknüpfungsspalten der inneren Verknüpfungstabelle vorhanden sein. Wenn es äußere AND gibt, müssen alle AND durch AND und den Gleichheitsoperator ( = ) verwenden.
  • Für materialisierte Ansichten mit CUBE , ROLLUP , Gruppierungssätzen oder deren Verkettung gelten die folgenden Einschränkungen:
    • Die SELECT Liste sollte einen Gruppierungsunterscheidungsmerkmal enthalten, der entweder eine GROUPING_ID Funktion für alle GROUP BY Ausdrücke oder eine GROUPING Funktion für jeden GROUP BY Ausdruck sein kann. Wenn die GROUP BY Klausel der materialisierten Ansicht beispielsweise " GROUP BY CUBE(a, b) " GROUPING_ID(a, b) sollte die SELECT Liste entweder " GROUPING_ID(a, b) " oder " GROUPING(a) AND GROUPING(b) "damit die materialisierte Ansicht schnell aktualisiert werden kann.
    • GROUP BY sollte nicht zu doppelten Gruppierungen führen. Beispielsweise kann " GROUP BY a, ROLLUP(a, b) " nicht schnell aktualisiert werden, da dies zu doppelten Gruppierungen " (a), (a, b), AND (a) " führt.

5.3.8.7 Einschränkungen bei der schnellen Aktualisierung materialisierter Ansichten mit UNION ALL

Materialisierte Ansichten mit dem Set-Operator UNION ALL unterstützen die Option REFRESH FAST wenn die folgenden Bedingungen erfüllt sind:
  • Die definierende Abfrage muss den Operator UNION ALL auf der obersten Ebene haben.

    Der UNION ALL Operator kann nicht in eine Unterabfrage eingebettet werden, mit einer Ausnahme: Der UNION ALL kann sich in einer Unterabfrage in der FROM Klausel befinden, vorausgesetzt, die definierende Abfrage hat die Form SELECT * FROM (Ansicht oder Unterabfrage mit UNION ALL ) wie im Folgenden Beispiel:
      CREATE VIEW view_with_unionall AS
     (SELECT c.rowid crid, c.cust_id, 2 umarker
      VON Kunden c WHERE c.cust_last_name = 'Smith'
      UNION ALL
      SELECT c.rowid crid, c.cust_id, 3 umarker
      VON Kunden c WHERE c.cust_last_name = 'Jones');
    
     MATERIALISIERTE ANSICHT ERSTELLEN unionall_inside_view_mv
     SCHNELL AUF NACHFRAGE WIEDERAUFNEHMEN
     SELECT * FROM view_with_unionall;
    
    Beachten Sie, dass die Ansicht view_with_unionall die Anforderungen für eine schnelle Aktualisierung erfüllt.
  • Jeder Abfrageblock in der UNION ALL Abfrage muss die Anforderungen einer schnell aktualisierbaren materialisierten Ansicht mit Aggregaten oder einer schnell aktualisierbaren materialisierten Ansicht mit Verknüpfungen erfüllen.

    Die entsprechenden Protokolle für materialisierte Ansichten müssen in den Tabellen erstellt werden, wie dies für den entsprechenden Typ der schnell aktualisierbaren materialisierten Ansicht erforderlich ist.
    Beachten Sie, dass die Oracle-Datenbank auch den Sonderfall einer materialisierten Ansicht einer einzelnen Tabelle mit ROWID sofern die Spalte ROWID in der Liste SELECT und im Protokoll der materialisierten Ansicht enthalten ist. Dies wird in der definierenden Abfrage der Ansicht view_with_unionall .
  • Die SELECT Liste jeder Abfrage muss einen UNION ALL Marker enthalten, und die UNION ALL Spalte muss in jedem UNION ALL Zweig einen eindeutigen konstanten numerischen Wert oder Zeichenfolgenwert haben. Außerdem muss die Markierungsspalte in der SELECT Liste jedes Abfrageblocks an derselben Ordnungsposition erscheinen. Weitere Informationen zu UNION ALL Markern finden Sie unter " UNION ALL-Marker und Umschreiben von Abfragen ".
  • Einige Funktionen wie äußere Verknüpfungen, Abfragen von materialisierten Ansichten mit nur Einfügung und Remote-Tabellen werden für materialisierte Ansichten mit UNION ALL nicht unterstützt. Beachten Sie jedoch, dass bei der Replikation verwendete materialisierte Ansichten, die keine Verknüpfungen oder Aggregate enthalten, schnell aktualisiert werden können, wenn UNION ALL oder Remote-Tabellen verwendet werden.
  • Der Kompatibilitätsinitialisierungsparameter muss auf 9.2.0 oder höher eingestellt sein, um mit UNION ALL eine schnell aktualisierbare materialisierte Ansicht zu erstellen.

Ich möchte Oracle-Fans nicht beleidigen, aber nach ihrer Liste von Einschränkungen zu urteilen, scheint es, dass dieser Mechanismus im allgemeinen Fall nicht mit einem Modell geschrieben wurde, sondern mit Tausenden von Indern, bei denen jeder seinen eigenen Thread schreiben durfte und jeder von ihnen konnte und tat. Die Verwendung dieses Mechanismus für echte Logik ist wie das Gehen in einem Minenfeld. Sie können jederzeit eine Mine erwerben, die auf eine der nicht offensichtlichen Einschränkungen stößt. Wie dies funktioniert, ist ebenfalls ein separates Thema, das jedoch nicht in den Geltungsbereich dieses Artikels fällt.

Microsoft SQL Server

Zusätzliche Anforderungen


Zusätzlich zu den SET-Optionen und den deterministischen Funktionsanforderungen müssen die folgenden Anforderungen erfüllt sein:
  • Der Benutzer, der CREATE INDEX ausführt, muss der Eigentümer der Ansicht sein.
  • Wenn Sie den Index erstellen, muss die Option IGNORE_DUP_KEY auf OFF (Standardeinstellung) gesetzt sein.
  • Tabellen müssen durch zweiteilige Namen, Schema , referenziert werden . Tabellenname in der Ansichtsdefinition.
  • Benutzerdefinierte Funktionen, auf die in der Ansicht verwiesen wird, müssen mit der Option WITH SCHEMABINDING .
  • Auf benutzerdefinierte Funktionen, auf die in der Ansicht verwiesen wird, muss durch den zweiteiligen Namen <Schema> verwiesen werden . <Funktion> .
  • Die Datenzugriffseigenschaft einer benutzerdefinierten Funktion muss NO SQL , und die externe Zugriffseigenschaft muss NO .
  • Common Language Runtime (CLR) -Funktionen können in der Auswahlliste der Ansicht angezeigt werden, können jedoch nicht Teil der Definition des Clustered-Indexschlüssels sein. CLR-Funktionen können nicht in der WHERE-Klausel der Ansicht oder der ON-Klausel einer JOIN-Operation in der Ansicht angezeigt werden.
  • Für CLR-Funktionen und -Methoden von benutzerdefinierten CLR-Typen, die in der Ansichtsdefinition verwendet werden, müssen die Eigenschaften wie in der folgenden Tabelle angegeben festgelegt sein.
    EigentumHinweis
    DETERMINISTIC = TRUEMuss explizit als Attribut der Microsoft .NET Framework-Methode deklariert werden.
    PRÄZISE = WAHRMuss explizit als Attribut der .NET Framework-Methode deklariert werden.
    DATENZUGRIFF = KEIN SQLWird ermittelt, indem das DataAccess-Attribut auf DataAccessKind.None und das SystemDataAccess-Attribut auf SystemDataAccessKind.None festgelegt werden.
    EXTERNER ZUGRIFF = NRDiese Eigenschaft ist für CLR-Routinen standardmäßig NO.
  • Die Ansicht muss mit der Option WITH SCHEMABINDING .
  • Die Ansicht darf nur auf Basistabellen verweisen, die sich in derselben Datenbank wie die Ansicht befinden. Die Ansicht kann nicht auf andere Ansichten verweisen.
  • Die SELECT-Anweisung in der Ansichtsdefinition darf die folgenden Transact-SQL-Elemente nicht enthalten:
    COUNTROWSET-Funktionen ( OPENDATASOURCE , OPENQUERY , OPENROWSET und OPENXML )OUTER ( OUTER , RIGHT oder FULL )
    Abgeleitete Tabelle (definiert durch Angabe einer SELECT Anweisung in der FROM Klausel)SelbstverbindungenAngeben von Spalten mithilfe von SELECT * oder SELECT <table_name>.*
    DISTINCTSTDEV , STDEVP , VAR , VARP oder AVGCommon Table Expression (CTE)
    float 1 , text , ntext , image , XML oder filestream spaltenUnterabfrageOVER Klausel, die Ranking- oder Aggregatfensterfunktionen enthält
    Volltext-Prädikate ( CONTAINS , FREETEXT )SUM Funktion, die auf einen nullbaren Ausdruck verweistORDER BY
    Benutzerdefinierte CLR-AggregatfunktionTOPOperatoren CUBE , GROUPING SETS oder GROUPING SETS
    MIN , MAXEXCEPT , INTERSECT oder INTERSECT OperatorenTABLESAMPLE
    TabellenvariablenOUTER APPLY oder CROSS APPLYPIVOT , UNPIVOT
    Sparse SpaltensätzeInline- (TVF) oder Tabellenfunktionen mit mehreren Anweisungen (MSTVF)OFFSET
    CHECKSUM_AGG

    1 Die indizierte Ansicht kann Float- Spalten enthalten. Solche Spalten können jedoch nicht in den Clustered-Indexschlüssel aufgenommen werden.
  • Wenn GROUP BY vorhanden ist, muss die VIEW-Definition COUNT_BIG(*) und darf HAVING nicht enthalten. Diese GROUP BY Einschränkungen gelten nur für die Definition der indizierten Ansicht. Eine Abfrage kann eine indizierte Ansicht in ihrem Ausführungsplan verwenden, auch wenn diese GROUP BY Einschränkungen nicht erfüllt sind.
  • Wenn die Ansichtsdefinition eine GROUP BY Klausel enthält, kann der Schlüssel des eindeutigen Clustered-Index nur auf die in der GROUP BY Klausel angegebenen Spalten verweisen.

Hier können Sie sehen, dass die Indianer nicht angezogen wurden, da sie beschlossen, nach dem Schema „Wir werden wenig, aber gut tun“ zu tun. Das heißt, sie haben mehr Minen auf dem Feld, aber ihr Standort ist transparenter. Das Beunruhigendste ist diese Einschränkung:
Die Ansicht darf nur auf Basistabellen verweisen, die sich in derselben Datenbank wie die Ansicht befinden. Die Ansicht kann nicht auf andere Ansichten verweisen.

In unserer Terminologie bedeutet dies, dass eine Funktion nicht auf eine andere materialisierte Funktion zugreifen kann. Es schneidet die ganze Ideologie im Keim.
Diese Einschränkung (und weiter im Text) reduziert auch die Anwendungsfälle erheblich:
Die SELECT-Anweisung in der Ansichtsdefinition darf die folgenden Transact-SQL-Elemente nicht enthalten:
COUNTROWSET-Funktionen ( OPENDATASOURCE , OPENQUERY , OPENROWSET und OPENXML )OUTER ( OUTER , RIGHT oder FULL )
Abgeleitete Tabelle (definiert durch Angabe einer SELECT Anweisung in der FROM Klausel)SelbstverbindungenAngeben von Spalten mithilfe von SELECT * oder SELECT <table_name>.*
DISTINCTSTDEV , STDEVP , VAR , VARP oder AVGCommon Table Expression (CTE)
float 1 , text , ntext , image , XML oder filestream spaltenUnterabfrageOVER Klausel, die Ranking- oder Aggregatfensterfunktionen enthält
Volltext-Prädikate ( CONTAINS , FREETEXT )SUM Funktion, die auf einen nullbaren Ausdruck verweistORDER BY
Benutzerdefinierte CLR-AggregatfunktionTOPOperatoren CUBE , GROUPING SETS oder GROUPING SETS
MIN , MAXEXCEPT , INTERSECT oder INTERSECT OperatorenTABLESAMPLE
TabellenvariablenOUTER APPLY oder CROSS APPLYPIVOT , UNPIVOT
Sparse SpaltensätzeInline- (TVF) oder Tabellenfunktionen mit mehreren Anweisungen (MSTVF)OFFSET
CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY und andere sind verboten. Vielleicht war es einfacher anzugeben, was verwendet werden kann als was nicht. Die Liste wäre wahrscheinlich viel kleiner.

Zusammenfassend lässt sich sagen, dass in jedem (ich stelle fest, kommerziellen) DBMS eine Vielzahl von Einschränkungen gegenüber keinem (mit Ausnahme eines logischen und nicht eines technischen) in der LGPL-Technologie bestehen. Es ist jedoch zu beachten, dass die Implementierung dieses Mechanismus in der relationalen Logik etwas komplizierter ist als in der beschriebenen Funktion.

Implementierung


Wie funktioniert es PostgreSQL wird als "virtuelle Maschine" verwendet. Im Inneren befindet sich ein komplexer Algorithmus, der Abfragen erstellt. Hier ist der Quellcode . Und es gibt nicht nur eine große Anzahl von Heuristiken mit einer Reihe von Wenns. Wenn Sie also ein paar Monate Zeit haben, um zu studieren, können Sie versuchen, die Architektur zu verstehen.

Funktioniert es effizient? Effektiv genug. Leider ist es schwierig, dies zu beweisen. Ich kann nur sagen, dass wenn Sie die Tausenden von Anfragen in großen Anwendungen berücksichtigen, diese im Durchschnitt effektiver sind als ein guter Entwickler. Ein ausgezeichneter SQL-Programmierer kann jede Abfrage effizienter schreiben, aber mit tausend Abfragen hat er einfach weder Motivation noch Zeit, dies zu tun. Das einzige, was ich jetzt als Beweis für die Wirksamkeit geben kann, ist, dass auf der Grundlage der auf diesem DBMS basierenden Plattform mehrere ERP-Systemprojekte funktionieren, in denen Tausende verschiedener MATERIALISIERTER Funktionen mit Tausenden von Benutzern und Terrabyte-Datenbanken mit Hunderten von Millionen von Datensätzen arbeiten auf einem normalen Dual-Prozessor-Server. Jeder kann jedoch die Effektivität testen / widerlegen, indem er die Plattform und PostgreSQL herunterlädt, die SQL-Abfrageprotokollierung aktiviert und versucht, die Logik und die Daten dort zu ändern.

In den folgenden Artikeln werde ich auch darüber sprechen, wie Sie Einschränkungen für Funktionen aufhängen, mit Änderungssitzungen arbeiten und vieles mehr können.

Source: https://habr.com/ru/post/de459066/


All Articles