
In meinem vorherigen Artikel habe ich das Konzept und die Implementierung einer Datenbank beschrieben, die auf Funktionen basiert, anstatt auf Tabellen und Feldern, wie es in relationalen Datenbanken der Fall ist. Viele Beispiele wurden präsentiert, die die Vorteile dieses Ansatzes im Vergleich zu klassischen Methoden verdeutlichen. Einige hielten diese Beispiele für nicht überzeugend genug.
In diesem Artikel werde ich zeigen, wie ein solches Konzept es ermöglicht, das Schreiben und Lesen in der Datenbank schnell und einfach zu balancieren, ohne die Logik der Funktionsweise zu ändern. Ähnliche Funktionen wurden in modernen kommerziellen Datenbanksystemen (insbesondere Oracle und Microsoft SQL Server) versucht umzusetzen. Am Ende des Artikels werde ich aufzeigen, dass ihre Ergebnisse, milde ausgedrückt, nicht besonders überzeugend waren.
Beschreibung
Wie bereits zuvor werde ich die Beschreibung zur besseren Verständlichkeit an Beispielen beginnen. Stellen wir uns vor, wir müssen eine Logik implementieren, die eine Liste von Abteilungen mit der Anzahl der Mitarbeiter und deren Gesamteinkommen zurückgibt.
In einer funktionalen Datenbank würde dies folgendermaßen aussehen:
CLASS Abteilung ‘Abteilung’;
name ‘Bezeichnung’ = DATENSTRING[100] (Abteilung);
CLASS Employee 'Mitarbeiter';
department 'Abteilung' = DATA Department (Employee);
salary 'Gehalt' = DATA NUMERIC[10,2] (Employee);
countEmployees 'Anzahl der Mitarbeiter' (Department d) =
GRUPPE SUMME 1 WENN Abteilung(Mitarbeiter e) = d;
GehaltSumme 'Gesamtgehalt' (Abteilung d) =
GRUPPE SUMME gehalt(Mitarbeiter e) WENN abteilung(e) = d;
WÄHLE name(Abteilung d), countMitarbeiter(d), GehaltSumme(d);
Die Komplexität der Ausführung dieser Abfrage in einem beliebigen DBMS wird gleich sein O(Anzahl der Mitarbeiter), da für diese Berechnung die gesamte Mitarbeiter-Tabelle gescannt und dann nach Abteilung gruppiert werden muss. Zudem wird es einen geringen (wir gehen davon aus, dass es deutlich mehr Mitarbeiter als Abteilungen gibt) Aufschlag in Abhängigkeit vom gewählten Plan geben. O(log Anzahl der Mitarbeiter) oder O(Anzahl der Abteilungen) für die Gruppierung und andere.
Es ist klar, dass die Kosten für die Ausführung in verschiedenen DBMS unterschiedlich sein können, aber die Komplexität bleibt unverändert.
In der vorgeschlagenen Implementierung wird das funktionale DBMS eine Unterabfrage generieren, die die erforderlichen Werte pro Abteilung berechnet, und anschließend einen JOIN mit der Abteilungstabelle durchführen, um den Namen zu erhalten. Für jede Funktion kann bei der Deklaration jedoch ein spezieller MARKER MATERIALIZED festgelegt werden. Das System erstellt automatisch das entsprechende Feld für jede solche Funktion. Bei Änderung des Funktionswerts wird auch der Feldwert innerhalb derselben Transaktion geändert. Bei Zugriff auf diese Funktion wird auf das bereits berechnete Feld zugegriffen.
Insbesondere wenn MATERIALIZED für Funktionen gesetzt wird countEmployees und salarySum, werden zwei Felder in der Abteilungstabelle hinzugefügt, die die Anzahl der Mitarbeiter und deren Gesamtgehalt speichern. Bei jeglicher Änderung der Mitarbeiter, deren Gehälter oder Zugehörigkeiten zu Abteilungen wird das System die Werte dieser Felder automatisch anpassen. Der oben genannte Befehl wird dann direkt auf diese Felder zugreifen und wird in O(Anzahl der Abteilungen).
Welche Einschränkungen gibt es? Nur eine: Diese Funktion muss eine endliche Anzahl von Eingabewerten haben, für die ihr Wert definiert ist. Ansonsten lässt sich eine Tabelle nicht erstellen, die all ihre Werte speichert, da es keine Tabelle mit einer unendlichen Anzahl von Zeilen geben kann.
Beispiel:
Mitarbeiteranzahl ‘Anzahl der Mitarbeiter mit einem Gehalt > N’ (Abteilung d, NUMERIC[10,2] N) =
GRUPPENSUMME Gehalt(Mitarbeiter e) WENN abteilung(e) = d UND gehalt(e) > N;
Diese Funktion ist für eine unendliche Anzahl von Werten der Zahl N definiert (zum Beispiel sind negative Werte geeignet). Daher kann sie nicht als MATERIALIZED gesetzt werden. Das ist also eine logische, keine technische Einschränkung (nicht, weil wir es nicht umsetzen konnten). Ansonsten gibt es keine Einschränkungen. Gruppierungen, Sortierungen, AND und OR, PARTITION, Rekursionen usw. können verwendet werden.
Beispielsweise kann in der Aufgabe 2.2 des vorherigen Artikels MATERIALIZED auf beide Funktionen gesetzt werden:
gekauft 'Kauft' (Kunde c, Produkt p, GANZZAHL y) =
GRUPPENSUMME sum(Detail d) WENN
kunde(bestellung(d)) = c UND
produkt(d) = p UND
extrahiereJahr(datum(bestellung(d))) = y MATERIALISIERT;
bewertung 'Bewertung' (Kunde c, Produkt p, GANZZAHL y) =
PARTITIONSSUMME 1 BESTELLEN DESC gekauft(c, p, y), p VON c, y MATERIALISIERT;
WÄHLEN contactName(Kunde c), name(Produkt p) WO bewertung(c, p, 1997) < 3;
Das System erstellt selbstständig eine Tabelle mit den Schlüsseltypen Kunde, Produkt und INTEGER, fügt zwei Felder hinzu und aktualisiert deren Werte bei Änderungen. Bei weiteren Zugriffen auf diese Funktionen erfolgt keine Berechnung, sondern es werden die Werte aus den entsprechenden Feldern gelesen.
Mit diesem Mechanismus können Sie beispielsweise rekursive Abfragen (CTE) vermeiden. Insbesondere betrachten wir Gruppen, die durch eine Eltern-Kind-Beziehung eine Baumstruktur bilden (jede Gruppe hat einen Bezug zu ihrem Elternteil):
Eltern = DATEN Gruppe (Gruppe);
In einer funktionalen Datenbank kann die Logik der Rekursion wie folgt definiert werden:
level (Group child, Group parent) = REKURSION 1l WENN child IST Gruppe UND parent == child
SCHRITT 2l WENN parent == parent($parent);
isParent (Group child, Group parent) = WAHR WENN level(child, parent) MATERIALISIERT;
Da für die Funktion isParent MATERIALIZED gesetzt ist, wird 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 ist. Die Anzahl der Datensätze in dieser Tabelle entspricht der Anzahl der Gruppen multipliziert mit der durchschnittlichen Baumtiefe. Wenn es beispielsweise erforderlich ist, die Anzahl der Nachkommen einer bestimmten Gruppe zu zählen, können Sie diese Funktion wie folgt ansprechen:
childrenCount (Gruppe g) = GRUPPENSUM 1 WENN isParent(Gruppe Kind, g);
Im SQL-Abfrage wird dabei kein CTE verwendet. Stattdessen erfolgt eine einfache GROUP BY-Anweisung.
Mit diesem Mechanismus können Sie auch bei Bedarf die Denormalisierung der Datenbank leicht durchführen:
CLASS Order 'Bestellung';
date 'Datum' = DATUM DATUM (Bestellung);
CLASS OrderDetail 'Bestellzeile';
order 'Bestellung' = DATA Order (OrderDetail);
date 'Datum' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;
Bei der Verwendung der Funktion date Die Bestellzeile wird aus einer Tabelle mit Bestellzeilen basierend auf dem Feld gelesen, für das ein Index besteht. Bei Änderungen des Bestelldatums wird das System automatisch das denormalisierte Datum in der Zeile neu berechnen.
Vorteile
Wozu dient dieser gesamte Mechanismus? In klassischen Datenbanksystemen können Entwickler oder DBAs ohne Neuschreiben der Abfragen nur die Indizes ändern, Statistiken definieren und dem Abfrageplaner Hinweise geben, wie sie ausgeführt werden sollen (Hinweise sind jedoch nur in kommerziellen Datenbanksystemen verfügbar). Egal wie sehr sie sich bemühen, sie können die erste Abfrage im Artikel nicht ausführen, ohne die Abfragen zu ändern und Trigger zu schreiben. Über (Anzahl der Abteilungen) ohne Änderungen an den Abfragen und ohne das Hinzufügen von Triggern. In dem vorgeschlagenen Schema kann man sich in der Entwicklungsphase keine Gedanken über die Datenstruktur und über die zu verwendenden Aggregationen machen. Das kann alles während des Betriebs ganz entspannt geändert werden.
In der Praxis sieht das folgendermaßen aus. Einige Personen entwickeln direkt die Logik basierend auf der gestellten Aufgabe. Sie haben keine Ahnung von Algorithmen und deren Komplexität, von Ausführungsplänen, von Join-Typen oder von anderen technischen Aspekten. Diese Personen sind eher Geschäftsanalytiker als Entwickler. Dann geht alles in die Test- oder Produktionsphase. Das Logging von langen Abfragen wird aktiviert. Wenn eine lange Abfrage entdeckt wird, entscheiden dann andere Personen (mehr technische, also im Prinzip DBAs) über die Aktivierung einer MATERIALIZED-Ansicht für eine bestimmte Zwischenfunktion. Dadurch wird die Schreibgeschwindigkeit etwas verlangsamt (da ein zusätzliches Feld in der Transaktion aktualisiert werden muss). Allerdings wird nicht nur diese Abfrage deutlich beschleunigt, sondern auch alle anderen, die diese Funktion nutzen. Die Entscheidung, welche Funktion materialisiert werden soll, ist dabei relativ einfach. Zwei Hauptparameter: Anzahl möglicher Eingabewerte (genau so viele Datensätze werden in der entsprechenden Tabelle vorhanden sein) und wie häufig sie in anderen Funktionen verwendet wird.
Analoga
Moderne kommerzielle DBMS verfügen über ähnliche Mechanismen: MATERIALIZED VIEW mit FAST REFRESH (Oracle) und INDEXED VIEW (Microsoft SQL Server). In PostgreSQL kann ein MATERIALIZED VIEW nicht innerhalb einer Transaktion aktualisiert werden, sondern nur auf Anfrage (und das unter sehr strengen Einschränkungen), weshalb wir diesen nicht berücksichtigen. Es gibt jedoch einige Probleme, die seine Verwendung erheblich einschränken.
Zunächst kann die Materialisierung nur aktiviert werden, wenn bereits eine normale VIEW erstellt wurde. Andernfalls müssten alle anderen Abfragen, die das neu erstellte View ansprechen, umgeschrieben werden, um diese Materialisierung zu nutzen. Alternativ könnte man alles beim Alten lassen, was jedoch mindestens ineffizient wäre, falls bereits bestimmte vorab berechnete Daten vorhanden sind, die durch viele Abfragen nicht immer genutzt, sondern neu berechnet werden.
Zweitens gibt es eine Vielzahl an Einschränkungen:
Oracle
5.3.8.4 Allgemeine Einschränkungen für Fast Refresh
Die definierende Abfrage der materialisierten Ansicht unterliegt den folgenden Einschränkungen:
- Die materialisierte Ansicht darf keine Referenzen auf sich wiederholende Ausdrücke wie enthalten:
SYSDATEundROWNUM.- Die materialisierte Ansicht darf keine Referenzen auf
RAWoderLONGRAWDatentypen enthalten.- Sie darf keine
SELECTListenunterabfragen enthalten.- Sie darf keine analytischen Funktionen (zum Beispiel,
RANK) in derSELECTKlausel enthalten.- Sie darf keine Referenzen auf eine Tabelle enthalten, für die ein
XMLIndexIndex definiert ist.- Sie darf keine
MODELKlausel enthalten.- Sie darf keine
HAVINGKlausel mit einer Unterabfrage enthalten.- Sie darf keine geschachtelten Abfragen enthalten, die
ANY,ALL, oderNOTEXISTS.- Sie darf keine
[START WITH …] VERBINDUNG HERSTELLENKlausel enthalten.- Es können keine mehreren Detail-Tabellen an unterschiedlichen Standorten enthalten sein.
EINBESTÄTIGENMaterialisierte Ansichten dürfen keine Remote-Detail-Tabellen haben.- Verschachtelte materialisierte Ansichten müssen eine Verknüpfung oder Aggregation haben.
- Materialisierte Verknüpfungsansichten und materialisierte Aggregatansichten mit einer
GRUPPENACHKlausel dürfen nicht aus einer indexorganisierten Tabelle auswählen.5.3.8.5 Einschränkungen für schnelles Aktualisieren von materialisierten Ansichten mit nur Verknüpfungen
Für die Definition von Abfragen für materialisierte Ansichten mit nur Verknüpfungen und ohne Aggregationen gelten die folgenden Einschränkungen für schnelles Aktualisieren:
- Alle Einschränkungen aus „«.
- Sie dürfen keine
GRUPPENACHKlauseln oder Aggregationen enthalten.- Die Rowids aller Tabellen in der
FROMListe müssen in derSELECTAbfrage erscheinen.- Materialisierte Ansicht-Protokolle müssen mit Rowids für alle Basis-Tabellen in der
FROMAbfrage erscheinen.- Es kann keine schnell aktualisierbare materialisierte Ansicht aus mehreren Tabellen mit einfachen Verknüpfungen erstellt werden, die eine Objekttyp-Spalte in der
SELECTAnweisung enthalten.Außerdem wird die von Ihnen gewählte Aktualisierungsmethode nicht optimal effizient sein, wenn:
- Die definierende Abfrage einen äußeren Join verwendet, der sich wie ein innerer Join verhält. Wenn die definierende Abfrage einen solchen Join enthält, ziehen Sie in Betracht, die definierende Abfrage so umzuschreiben, dass sie einen inneren Join enthält.
- Die
SELECTListe der materialisierten Ansicht enthält Ausdrücke über Spalten aus mehreren Tabellen.5.3.8.6 Einschränkungen für schnelles Aktualisieren von materialisierten Ansichten mit Aggregationen
Für die Definition von Abfragen für materialisierte Ansichten mit Aggregationen oder Verknüpfungen gelten die folgenden Einschränkungen für schnelles Aktualisieren:
- Alle Einschränkungen aus „«.
Schnelles Aktualisieren wird für beide
EINBESTÄTIGENundEINFORDERUNGmaterialisierte Ansichten unterstützt, jedoch gelten die folgenden Einschränkungen:
- Alle Tabellen in der materialisierten Ansicht müssen materialisierte Ansicht-Protokolle haben, und die materialisierten Ansicht-Protokolle müssen:
- Alle Spalten der in der materialisierten Ansicht referenzierten Tabelle enthalten.
- Mit
ROWIDundEINSCHLIESSENNEUWERTE.- Die
SEQUENZKlausel angeben, wenn die Tabelle voraussichtlich eine Mischung aus Einfügungen/Direktladungen, Löschungen und Aktualisierungen haben wird.- Nur
SUMME,ANZAHL,DURCHSCHNITT,STANDDEV,VARIANZ,MINundMAXwerden für schnelles Aktualisieren unterstützt.ANZAHL(*)muss angegeben werden.- Aggregatfunktionen dürfen nur als äußerster Teil des Ausdrucks auftreten. Das heißt, Aggregationen wie
AVG(AVG(x))oderAVG(x)+AVG(x)sind nicht erlaubt.- Für jedes Aggregat wie
AVG(expr), muss das entsprechendeCOUNT(expr)vorhanden sein. Oracle empfiehlt, dassSUM(expr)angegeben wird.- Wenn
VARIANCE(expr)oderSTDDEV(expr) angegeben ist,COUNT(expr)undSUM(expr)muss angegeben werden. Oracle empfiehlt, dassSUM(expr * expr)angegeben wird.- Die
SELECTSpalte in der definierenden Abfrage kann kein komplexer Ausdruck mit Spalten aus mehreren Basistabellen sein. Ein möglicher Workaround ist die Verwendung einer geschachtelten materialisierten Ansicht.- Die
SELECTDie Liste muss alleGRUPPENACHSpalten enthalten.- Die materialisierte Ansicht basiert nicht auf einer oder mehreren entfernten Tabellen.
- Wenn Sie einen
CHARDatentyp in den Filterspalten eines materialisierten Sichtprotokolls verwenden, müssen die Zeichencodierungen der Master-Website und der materialisierten Ansicht übereinstimmen.- Wenn die materialisierte Ansicht eine der folgenden Eigenschaften hat, wird ein schneller Refresh nur bei konventionellen DML-Einfügungen und direkten Ladevorgängen unterstützt.
- Materialisierte Ansichten mit
MINoderMAXAggregaten- Materialisierte Ansichten, die
SUM(expr)aber keineCOUNT(expr)- Materialisierte Ansichten ohne
ANZAHL(*)Eine solche materialisierte Ansicht wird als Insert-Only-Materialized View bezeichnet.
- Eine materialisierte Ansicht mit
MAXoderMINist nach Lösch- oder gemischten DML-Anweisungen schnell aktualisierbar, wenn sie keinWHEREKlausel enthalten.
Der Max/Min-Schnell-Refresh nach Lösch- oder gemischten DML-Anweisungen verhält sich nicht wie im Insert-Only-Fall. Es werden die Max/Min-Werte für die betroffenen Gruppen gelöscht und neu berechnet. Sie müssen sich seiner Leistungsauswirkungen bewusst sein.- Materialisierte Ansichten mit benannten Ansichten oder Unterabfragen in der
FROMKlausel können schnell aktualisiert werden, wenn die Ansichten vollständig zusammengeführt werden können. Informationen darüber, welche Ansichten zusammengeführt werden, finden Sie in .- Wenn keine äußeren Joins vorhanden sind, können Sie willkürliche Auswahlen und Joins in der
WHEREKlausel enthalten.- Materialisierte Aggregatansichten mit äußeren Verknüpfungen sind schnell aktualisierbar nach konventionellen DML und direkten Ladeoperationen, vorausgesetzt, dass nur die äußere Tabelle verändert wurde. Außerdem müssen einzigartige Einschränkungen an den Verknüpfungsspalten der inneren Verknüpfungstabelle bestehen. Wenn äußere Verknüpfungen vorhanden sind, müssen alle Verknüpfungen durch
ANDund müssen den Gleichheits-(=) Operator verwenden.- Für materialisierte Ansichten mit
CUBE,ROLLUP, Gruppierungssets oder deren Kombinationen gelten die folgenden Einschränkungen:
- Die
SELECTDie Liste sollte ein Gruppierungsunterscheidung enthalten, die entweder eineGROUPING_ID-Funktion auf allenGRUPPENACHAusdrücken oderGROUPING-Funktionen für jedenGRUPPENACHAusdruck. Zum Beispiel, wenn dieGRUPPENACHKlausel der materialisierten Ansicht «GRUPPENACHCUBE(a, b)« ist, dann sollte die Liste entweder «SELECTGROUPING_ID(a, b)» oder «GROUPING(a)GROUPING(b)AND» enthalten, damit die materialisierte Ansicht schnell aktualisierbar ist.sollte keine doppelten Gruppierungen ergeben. Zum Beispiel, «GRUPPENACHGROUP BY a, ROLLUP(a, b)» ist nicht schnell aktualisierbar, da es zu doppelten Gruppierungen «(a), (a, b), UND (a)führt.«.5.3.8.7 Einschränkungen für schnelles Aktualisieren von materialisierten Ansichten mit UNION ALL
Materialisierte Ansichten mit dem
UNIONALLMengenoperator unterstützen dieSchnellaktualisierungOPTION, wenn die folgenden Bedingungen erfüllt sind:Die definierende Abfrage muss den
- Operator an oberster Stelle haben.
UNIONALLDer Operator darf nicht in einer Unterabfrage eingebettet sein, mit einer Ausnahme: DerDie
UNIONALLkann in einer Unterabfrage in derUNIONALLKlausel sein, sofern die definierende Abfrage die Form hatFROMSELECT * FROM(Ansicht oder Unterabfrage mit) wie im folgenden Beispiel:UNIONALLCREATE 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;Beachten Sie, dass die Ansichtview_with_unionall
die Anforderungen für eine schnelle Aktualisierung erfüllt.Jeder Abfrageblock in der- Jeder Abfrageblock in der
UNIONALLDie Abfrage muss die Anforderungen an eine schnell aktualisierbare materielles Sichtfeld mit Aggregaten oder an eine schnell aktualisierbare materielles Sichtfeld mit Joins erfüllen.Die entsprechenden Logs für materielle Sichten müssen entsprechend dem erforderlichen Typ der schnell aktualisierbaren materiellen Sichtungen auf den Tabellen erstellt werden.
Beachten Sie, dass die Oracle-Datenbank auch den Sonderfall einer materiellen Sicht mit nur einem einzelnen Joins einer Tabelle erlaubt, vorausgesetzt, dieROWIDSpalte ist in dieSELECTListe und ins Log der materiellen Sicht aufgenommen worden. Dies wird in der definierten Abfrage der Sicht dargestellt.die Anforderungen für eine schnelle Aktualisierung erfüllt..- Die
SELECTDie Liste jeder Abfrage muss einUNIONALLMarker enthalten, und dieUNIONALLSpalte muss in jedemUNIONALLZweig einen eindeutigen konstanten numerischen oder Zeichenwert haben. Darüber hinaus muss die Markerspalte in der gleichen ordinalen Position in derSELECTListe jedes Abfrageblocks erscheinen. Siehe «» für weitere Informationen zuUNIONALLMarkern.- Einige Funktionen wie äußere Joins, nur Einfüge-Aggregate aus der Sicht der materiellen Abfragen und entfernte Tabellen werden für materielle Sichten mit
UNIONALLnicht unterstützt. Beachten Sie jedoch, dass materielle Sichten, die in der Replikation verwendet werden und die keine Joins oder Aggregationen enthalten, schnell aktualisiert werden können, wennUNIONALLoder entfernte Tabellen verwendet werden.- Der Kompatibilitäts-Initialisierungsparameter muss auf 9.2.0 oder höher eingestellt sein, um eine schnell aktualisierbare materielle Sicht zu erstellen.
UNIONALL.
Ich möchte die Oracle-Anhänger nicht beleidigen, aber angesichts ihrer Liste von Einschränkungen entsteht der Eindruck, dass dieser Mechanismus nicht für den allgemeinen Gebrauch geschrieben wurde. Es sieht aus, als hätte eine große Zahl indischer Entwickler an verschiedenen Versionen gearbeitet, wobei jeder das beigetragen hat, was er konnte. Die Nutzung dieses Mechanismus für echte Logik gleicht dem Gehen durch ein Minenfeld. Jederzeit kann man auf eine der nicht offensichtlichen Einschränkungen stoßen. Wie dies funktioniert, ist ebenfalls eine eigene Frage, die jedoch den Rahmen dieses Artikels sprengt.
Microsoft SQL Server
Zusätzliche Anforderungen
Neben den SET-Optionen und den Anforderungen an deterministische Funktionen müssen die folgenden Anforderungen erfüllt sein:
- Der Benutzer, der ausführt
CREATE INDEXmuss der Eigentümer der Ansicht sein.- Beim Erstellen des Index muss die
IGNORE_DUP_KEYOption auf AUS (Standard-Einstellung) gesetzt sein.- Tabellen müssen mit zweigeteilten Namen referenziert werden, Schema.Tabellenname in der Definitionsansicht.
- Benutzerdefinierte Funktionen, die in der Ansicht referenziert werden, müssen mit der
WITH SCHEMABINDINGOption erstellt werden.- Alle in der Ansicht referenzierten benutzerdefinierten Funktionen müssen mit zweigeteilten Namen referenziert werden, <schema>.<function>.
- Die Datenzugriffseigenschaft einer benutzerdefinierten Funktion muss
NO SQL, und die externe Zugriffs-Eigenschaft mussNEIN.- Gemeinsame Sprachlaufzeit (CLR)-Funktionen können in der Auswahlliste der Ansicht erscheinen, dürfen jedoch nicht Teil der Definition des Schlüsselindex der Gruppierung sein. CLR-Funktionen dürfen nicht in der WHERE-Klausel der Ansicht oder der ON-Klausel einer JOIN-Operation in der Ansicht erscheinen.
- Die CLR-Funktionen und Methoden von benutzerdefinierten CLR-Typen, die in der Sichtdefinition verwendet werden, müssen die Eigenschaften wie in der folgenden Tabelle angegeben festgelegt haben.
Eigenschaft
HinweisDETERMINISTIC = TRUE
Muss ausdrücklich als Attribut der Microsoft .NET Framework-Methode deklariert werden.PRECISE = TRUE
Muss ausdrücklich als Attribut der .NET Framework-Methode deklariert werden.DATA ACCESS = NO SQL
Bestimmt durch Festlegen des DataAccess-Attributs auf DataAccessKind.None und des SystemDataAccess-Attributs auf SystemDataAccessKind.None.EXTERNAL ACCESS = NO
Diese Eigenschaft ist standardmäßig auf NEIN für CLR-Routinen eingestellt.- Die Sicht muss unter Verwendung der
WITH SCHEMABINDINGOption erstellt werden.- Die Sicht darf nur Basis-Tabellen referenzieren, die sich in derselben Datenbank wie die Sicht befinden. Die Sicht darf keine anderen Sichten referenzieren.
- Die SELECT-Anweisung in der Sichtdefinition darf folgende Transact-SQL-Elemente nicht enthalten:
ANZAHL
ROWSET-Funktionen (OPENDATASOURCE,OPENQUERY,OPENROWSET, UNDOPENXML)
OUTERVerknüpfungen (LEFT,RIGHT, oderFULL)Abgeleitete Tabelle (definiert durch Angabe einer
SELECTAnweisung imFROMAbschnitt)
Selbstverknüpfungen
Spalten mithilfe vonSELECT *oderSELECT.*
DISTINCT
STDEV,STDEVP,VAR,VARP, oderDURCHSCHNITT
Gemeinsame Tabellenausdrücke (CTE)float1, text, ntext, image, XML, oder filestream Spalten
Unterabfrage
OVERAbschnitt, der Rang- oder Aggregatfensterfunktionen enthältVolltextprädikate (
CONTAINS,FREETEXT)
SUMMEFunktion, die einen nullable Ausdruck referenziert
ORDER BYCLR benutzerdefinierte Aggregatfunktion
TOP
CUBE,ROLLUP, oderGROUPING SETSOperatoren
MIN,MAX
UNION,EXCEPT, oderINTERSECTOperatoren
TABLESAMPLETabellenvariablen
OUTER APPLYoderCROSS APPLY
PIVOT,UNPIVOTSparse-Spaltenmengen
Inline (TVF) oder mehrstückige tabellenwertige Funktionen (MSTVF)
OFFSET
CHECKSUM_AGG1 Die indizierte Sicht kann enthalten float Spalten; solche Spalten dürfen jedoch nicht im Schlüssel des Cluster-Indexes enthalten sein.
- Wenn
GROUP BYist vorhanden, muss die DEFINITION DER SICHT enthaltenCOUNT_BIG(*)und darf nicht enthaltenHAVING. DieseGROUP BYEinschränkungen gelten nur für die Definition der indizierten Sicht. Eine Abfrage kann eine indizierte Sicht in ihrem Ausführungsplan verwenden, auch wenn sie dieseGROUP BYEinschränkungen nicht erfüllt.- Wenn die Sichtdefinition eine enthält
GROUP BYIn der Klausel kann der Schlüssel des einzigartigen, gruppierten Index nur auf die angegebenen Spalten verweisen.GROUP BYKlausel enthalten.Hier sieht man, dass die Inder nicht angezogen wurden, da sie sich entschieden haben, nach dem Motto 'Wenig, aber gut' zu arbeiten. Das heißt, sie haben zwar mehr Minen auf dem Feld, aber deren Anordnung ist transparenter. Am meisten ärgert jedoch diese Einschränkung:
Die Sicht darf nur Basis-Tabellen referenzieren, die sich in derselben Datenbank wie die Sicht befinden. Die Sicht darf keine anderen Sichten referenzieren.
In unserer Terminologie bedeutet das, dass die Funktion nicht auf eine andere materialisierte Funktion zugreifen kann. Das schneidet die gesamte Ideologie im Keim ab.
Diese Einschränkung (und die folgenden Texte) reduziert die Einsatzmöglichkeiten erheblich:Die SELECT-Anweisung in der Sichtdefinition darf folgende Transact-SQL-Elemente nicht enthalten:
ANZAHL
ROWSET-Funktionen (OPENDATASOURCE,OPENQUERY,OPENROWSET, UNDOPENXML)
OUTERVerknüpfungen (LEFT,RIGHT, oderFULL)Abgeleitete Tabelle (definiert durch Angabe einer
SELECTAnweisung imFROMAbschnitt)
Selbstverknüpfungen
Spalten mithilfe vonSELECT *oderSELECT.*
DISTINCT
STDEV,STDEVP,VAR,VARP, oderDURCHSCHNITT
Gemeinsame Tabellenausdrücke (CTE)float1, text, ntext, image, XML, oder filestream Spalten
Unterabfrage
OVERAbschnitt, der Rang- oder Aggregatfensterfunktionen enthältVolltextprädikate (
CONTAINS,FREETEXT)
SUMMEFunktion, die einen nullable Ausdruck referenziert
ORDER BYCLR benutzerdefinierte Aggregatfunktion
TOP
CUBE,ROLLUP, oderGROUPING SETSOperatoren
MIN,MAX
UNION,EXCEPT, oderINTERSECTOperatoren
TABLESAMPLETabellenvariablen
OUTER APPLYoderCROSS APPLY
PIVOT,UNPIVOTSparse-Spaltenmengen
Inline (TVF) oder mehrstückige tabellenwertige Funktionen (MSTVF)
OFFSET
CHECKSUM_AGGOUTER JOINS, UNION, ORDER BY und andere sind nicht erlaubt. Es wäre wahrscheinlich einfacher gewesen, zu sagen, was verwendet werden kann, als was nicht erlaubt ist. Die Liste wäre wahrscheinlich viel kürzer gewesen.
Zusammenfassend lässt sich sagen: Ein riesiger Satz von Einschränkungen in jeder (ich bemerke kommerziellen) DBMS vs. keine (außer einer logischen, nicht technischen) in der LGPL-Technologie. Es sollte jedoch beachtet werden, dass die Implementierung dieses Mechanismus in relationaler Logik etwas komplizierter ist als in der beschriebenen funktionalen.
Implementierung
Wie funktioniert das? Als 'virtuelle Maschine' wird PostgreSQL verwendet. Innen gibt es einen komplexen Algorithmus, der sich mit dem Aufbau von Abfragen beschäftigt. Hier ist . Und es handelt sich nicht nur um eine große Sammlung von Heuristiken mit einer Menge von If-Bedingungen. Wenn Sie also ein paar Monate Zeit haben, können Sie versuchen, sich mit der Architektur vertraut zu machen.
Funktioniert das effizient? Ziemlich effizient. Leider ist es schwer, das zu beweisen. Ich kann nur sagen, dass im Durchschnitt Tausende von Anfragen in großen Anwendungen effizienter sind als bei einem guten Entwickler. Ein ausgezeichneter SQL-Programmierer kann jede Anfrage effizienter schreiben, aber bei einer Flut von Anfragen hat er einfach nicht die Motivation oder die Zeit dafür. Das Einzige, was ich als Beweis für die Effizienz anführen kann, ist, dass auf der Basis dieser Datenbank einige Projekte basieren. , in denen es Tausende von verschiedenen MATERIALIZED Funktionen gibt, mit Tausenden von Nutzern und Terabyte großen Datenbanken mit Hunderten von Millionen von Einträgen, die auf einem ganz normalen Dual-Prozessor-Server betrieben werden. Jeder, der möchte, kann die Effizienz überprüfen oder in Frage stellen, indem er und PostgreSQL herunterlädt, SQL-Logging aktiviert und versucht, die Logik und Daten dort anzupassen.
In den folgenden Artikeln werde ich außerdem erklären, wie man Einschränkungen für Funktionen festlegen kann, wie man mit Sitzungen arbeitet, Änderungen vornimmt und vieles mehr.
Quelle: habr.comKaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster
