Équilibrer les écritures et les lectures dans une base de données

Équilibrer les écritures et les lectures dans une base de données
Dans le précédent article J'ai décrit le concept et la mise en œuvre d'une base de données construite sur la base de fonctions, plutôt que de tables et de champs comme dans les bases de données relationnelles. Il a fourni de nombreux exemples montrant les avantages de cette approche par rapport à la méthode classique. Beaucoup les ont trouvés pas assez convaincants.

Dans cet article, je vais montrer comment ce concept vous permet d'équilibrer rapidement et facilement les écritures et les lectures dans la base de données sans aucun changement dans la logique de fonctionnement. Des fonctionnalités similaires ont été tentées d'être implémentées dans les SGBD commerciaux modernes (en particulier Oracle et Microsoft SQL Server). À la fin de l’article, je montrerai que ce qu’ils ont fait, c’est un euphémisme, n’a pas très bien fonctionné.

description

Comme précédemment, pour une meilleure compréhension, je commencerai la description par des exemples. Disons que nous devons mettre en œuvre une logique qui renverra une liste de départements avec le nombre d'employés et leur salaire total.

Dans une base de données fonctionnelle, cela ressemblerait à ceci :

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

La complexité de l'exécution de cette requête dans n'importe quel SGBD sera équivalente à O(nombre d'employés)car ce calcul nécessite de scanner l'intégralité du tableau des salariés puis de les regrouper par service. Il y aura également quelques petits suppléments (nous pensons qu'il y a beaucoup plus d'employés que de départements) en fonction du plan choisi. O (journal du nombre d'employés) ou O(nombre de départements) pour le regroupement et ainsi de suite.

Il est clair que la surcharge d'exécution peut être différente selon les SGBD, mais la complexité ne changera en rien.

Dans l'implémentation proposée, le SGBD fonctionnel générera une sous-requête qui calculera les valeurs requises pour le département, puis effectuera un JOIN avec la table département pour obtenir le nom. Cependant, pour chaque fonction, lors de la déclaration, il est possible de définir un marqueur MATÉRIAU spécial. Le système créera automatiquement un champ correspondant pour chacune de ces fonctions. Lors de la modification de la valeur d'une fonction, la valeur du champ changera également dans la même transaction. En accédant à cette fonction, on accédera au champ pré-calculé.

En particulier, si vous définissez MATÉRIAU pour les fonctions compterEmployés и salaireSomme, puis deux champs seront ajoutés au tableau avec la liste des départements, qui stockera le nombre d'employés et leur salaire total. Chaque fois qu'il y a un changement dans les employés, leurs salaires ou leurs affiliations à un service, le système modifiera automatiquement les valeurs de ces champs. La requête ci-dessus accédera directement à ces champs et sera exécutée dans O(nombre de départements).

Quelles sont les restrictions ? Une seule chose : une telle fonction doit avoir un nombre fini de valeurs d'entrée pour lesquelles sa valeur est définie. Sinon, il sera impossible de construire une table contenant toutes ses valeurs, car il ne peut pas y avoir de table avec un nombre infini de lignes.

Exemple:

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

Cette fonction est définie pour un nombre infini de valeurs de N (par exemple, toute valeur négative convient). Par conséquent, vous ne pouvez pas y mettre MATÉRIEL. Il s’agit donc d’une limitation logique, et non technique (c’est-à-dire pas parce que nous n’avons pas pu l’implémenter). Sinon, il n'y a aucune restriction. Vous pouvez utiliser des regroupements, des tris, AND et OR, PARTITION, récursivité, etc.

Par exemple, dans le problème 2.2 de l'article précédent, vous pouvez mettre MATERIALIZED sur les deux fonctions :

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;

Le système lui-même créera une table avec des clés de type Témoignages, Produit и INTEGER, y ajoutera deux champs et mettra à jour les valeurs des champs avec toutes les modifications. Lorsque d'autres appels à ces fonctions seront effectués, ils ne seront pas calculés, mais plutôt les valeurs seront lues à partir des champs correspondants.

Grâce à ce mécanisme, vous pouvez, par exemple, vous débarrasser des récursions (CTE) dans les requêtes. Considérons en particulier les groupes qui forment un arbre utilisant la relation enfant/parent (chaque groupe a un lien vers son parent) :

parent = DATA Group (Group);

Dans une base de données fonctionnelle, la logique de récursivité peut être spécifiée comme suit :

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;

Puisque pour la fonction estParent est marqué MATÉRIAU, alors une table avec deux clés (groupes) sera créée pour cela, dans laquelle le champ estParent ne sera vrai que si la première clé est un enfant de la seconde. Le nombre d'entrées dans ce tableau sera égal au nombre de groupes multiplié par la profondeur moyenne de l'arbre. Si vous avez besoin, par exemple, de compter le nombre de descendants d'un certain groupe, vous pouvez utiliser cette fonction :

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

Il n'y aura pas de CTE dans la requête SQL. Au lieu de cela, il y aura un simple GROUP BY.

Grâce à ce mécanisme, vous pouvez également facilement dénormaliser la base de données si nécessaire :

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

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

Lors de l'appel d'une fonction données pour la ligne de commande, le champ pour lequel il existe un index sera lu dans la table des lignes de commande. Lorsque la date de commande change, le système lui-même recalculera automatiquement la date dénormalisée dans la ligne.

avantages

A quoi sert tout ce mécanisme ? Dans les SGBD classiques, sans réécrire les requêtes, un développeur ou un administrateur de base de données peut uniquement modifier les index, déterminer des statistiques et indiquer au planificateur de requêtes comment les exécuter (et les HINT ne sont disponibles que dans les SGBD commerciaux). Peu importe leurs efforts, ils ne pourront pas répondre à la première requête de l'article dans O (nombre de départements) sans modifier les requêtes ni ajouter de déclencheurs. Dans le schéma proposé, au stade du développement, vous n’avez pas à penser à la structure de stockage des données ni aux agrégations à utiliser. Tout cela peut être facilement modifié à la volée, directement en fonctionnement.

En pratique, cela ressemble à ceci. Certaines personnes développent une logique directement basée sur la tâche à accomplir. Ils ne comprennent pas les algorithmes et leur complexité, ni les plans d'exécution, ni les types de jointures, ni aucun autre composant technique. Ces personnes sont plus des analystes commerciaux que des développeurs. Ensuite, tout cela passe en test ou en exploitation. Permet la journalisation des requêtes de longue durée. Lorsqu'une requête longue est détectée, d'autres personnes (plus techniques - essentiellement DBA) décident d'activer MATERIALIZED sur une fonction intermédiaire. Cela ralentit un peu l'enregistrement (puisque cela nécessite de mettre à jour un champ supplémentaire dans la transaction). Cependant, non seulement cette requête est considérablement accélérée, mais également toutes les autres qui utilisent cette fonction. Dans le même temps, il est relativement facile de décider quelle fonction matérialiser. Deux paramètres principaux : le nombre de valeurs d'entrée possibles (c'est le nombre d'enregistrements qui seront dans la table correspondante) et la fréquence à laquelle elle est utilisée dans d'autres fonctions.

Analogues

Les SGBD commerciaux modernes ont des mécanismes similaires : VUE MATÉRIELLE avec FAST REFRESH (Oracle) et VUE INDEXÉE (Microsoft SQL Server). Dans PostgreSQL, la VUE MATÉRIELLE ne peut pas être mise à jour dans une transaction, mais uniquement sur demande (et même avec des restrictions très strictes), nous ne la considérons donc pas. Mais ils rencontrent plusieurs problèmes qui limitent considérablement leur utilisation.

Premièrement, vous ne pouvez activer la matérialisation que si vous avez déjà créé une VUE standard. Sinon, vous devrez réécrire les requêtes restantes pour accéder à la vue nouvellement créée afin d'utiliser cette matérialisation. Ou laissez tout tel quel, mais ce sera au moins inefficace s'il existe certaines données déjà pré-calculées, mais de nombreuses requêtes ne les utilisent pas toujours, mais les recalculent.

Deuxièmement, ils ont un grand nombre de restrictions :

Oracle

5.3.8.4 Restrictions générales sur l'actualisation rapide

La requête de définition de la vue matérialisée est restreinte comme suit :

  • La vue matérialisée ne doit pas contenir de références à des expressions non répétitives telles que SYSDATE ainsi que ROWNUM.
  • La vue matérialisée ne doit pas contenir de références à RAW or LONG RAW Types de données.
  • Il ne peut pas contenir un SELECT sous-requête de liste.
  • Il ne peut pas contenir de fonctions analytiques (par exemple, RANK) Dans le SELECT clause.
  • Il ne peut pas référencer une table sur laquelle un XMLIndex l'index est défini.
  • Il ne peut pas contenir un MODEL clause.
  • Il ne peut pas contenir un HAVING clause avec une sous-requête.
  • Il ne peut pas contenir de requêtes imbriquées ayant ANY, ALLou NOT EXISTS.
  • Il ne peut pas contenir un [START WITH …] CONNECT BY clause.
  • Il ne peut pas contenir plusieurs tables détaillées sur différents sites.
  • ON COMMIT les vues matérialisées ne peuvent pas avoir de tables de détails distantes.
  • Les vues matérialisées imbriquées doivent avoir une jointure ou un agrégat.
  • Vues de jointure matérialisées et vues agrégées matérialisées avec un GROUP BY La clause ne peut pas effectuer de sélection à partir d'une table organisée en index.

5.3.8.5 Restrictions sur l'actualisation rapide sur les vues matérialisées avec jointures uniquement

La définition de requêtes pour des vues matérialisées avec des jointures uniquement et aucun agrégat présente les restrictions suivantes en matière d'actualisation rapide :

  • Toutes les restrictions de «Restrictions générales sur l'actualisation rapide«.
  • Ils ne peuvent pas avoir GROUP BY clauses ou agrégats.
  • Rowids de toutes les tables du FROM la liste doit apparaître dans le SELECT liste de la requête.
  • Les journaux de vues matérialisées doivent exister avec des ID de ligne pour toutes les tables de base du FROM liste de la requête.
  • Vous ne pouvez pas créer une vue matérialisée à actualisation rapide à partir de plusieurs tables avec des jointures simples incluant une colonne de type d'objet dans le SELECT déclaration.

De plus, la méthode d’actualisation que vous choisissez ne sera pas efficace de manière optimale si :

  • La requête de définition utilise une jointure externe qui se comporte comme une jointure interne. Si la requête de définition contient une telle jointure, envisagez de réécrire la requête de définition pour qu'elle contienne une jointure interne.
  • La SELECT La liste de la vue matérialisée contient des expressions sur les colonnes de plusieurs tables.

5.3.8.6 Restrictions sur l'actualisation rapide des vues matérialisées avec des agrégats

La définition de requêtes pour des vues matérialisées avec des agrégats ou des jointures présente les restrictions suivantes en matière d'actualisation rapide :

L'actualisation rapide est prise en charge pour les deux ON COMMIT ainsi que ON DEMAND vues matérialisées, mais les restrictions suivantes s'appliquent :

  • Toutes les tables de la vue matérialisée doivent avoir des journaux de vue matérialisée, et les journaux de vue matérialisée doivent :
    • Contient toutes les colonnes de la table référencée dans la vue matérialisée.
    • Précisez avec ROWID ainsi que INCLUDING NEW VALUES.
    • Spécifie le SEQUENCE si la table doit contenir un mélange d'insertions/chargements directs, de suppressions et de mises à jour.

  • Seulement SUM, COUNT, AVG, STDDEV, VARIANCE, MIN ainsi que MAX sont pris en charge pour un rafraîchissement rapide.
  • COUNT(*) doit être spécifié.
  • Les fonctions d'agrégation doivent apparaître uniquement comme partie la plus externe de l'expression. Autrement dit, des agrégats tels que AVG(AVG(x)) or AVG(x)+ AVG(x) ne sont pas permis.
  • Pour chaque agrégat tel que AVG(expr), le correspondant COUNT(expr) presence obligatoire. Oracle recommande que SUM(expr) être spécifié.
  • If VARIANCE(expr) or STDDEV(expr) est spécifié, COUNT(expr) ainsi que SUM(expr) doit être précisé. Oracle recommande que SUM(expr *expr) être spécifié.
  • La SELECT La colonne dans la requête de définition ne peut pas être une expression complexe avec des colonnes provenant de plusieurs tables de base. Une solution possible à ce problème consiste à utiliser une vue matérialisée imbriquée.
  • La SELECT la liste doit contenir tous GROUP BY colonnes.
  • La vue matérialisée ne repose pas sur une ou plusieurs tables distantes.
  • Si vous utilisez un CHAR type de données dans les colonnes de filtre d'un journal de vue matérialisée, les jeux de caractères du site maître et de la vue matérialisée doivent être identiques.
  • Si la vue matérialisée présente l'un des éléments suivants, l'actualisation rapide est prise en charge uniquement sur les insertions DML conventionnelles et les chargements directs.
    • Vues matérialisées avec MIN or MAX agrégats
    • Vues matérialisées qui ont SUM(expr) mais non COUNT(expr)
    • Vues matérialisées sans COUNT(*)

    Une telle vue matérialisée est appelée vue matérialisée à insertion uniquement.

  • Une vue matérialisée avec MAX or MIN est rapidement actualisable après des instructions de suppression ou DML mixtes s'il n'a pas de WHERE clause.
    L'actualisation rapide max/min après suppression ou DML mixte n'a pas le même comportement que le cas d'insertion uniquement. Il supprime et recalcule les valeurs max/min pour les groupes concernés. Vous devez être conscient de son impact sur les performances.
  • Vues matérialisées avec des vues nommées ou des sous-requêtes dans le FROM La clause peut être rapidement actualisée à condition que les vues puissent être complètement fusionnées. Pour plus d'informations sur les vues qui seront fusionnées, voir Référence du langage SQL de base de données Oracle.
  • S'il n'y a pas de jointures externes, vous risquez d'avoir des sélections et des jointures arbitraires dans le WHERE clause.
  • Les vues agrégées matérialisées avec jointures externes sont rapidement actualisables après des chargements DML et directs conventionnels, à condition que seule la table externe ait été modifiée. En outre, des contraintes uniques doivent exister sur les colonnes de jointure de la table de jointure interne. S'il y a des jointures externes, toutes les jointures doivent être connectées par ANDs et doit utiliser l'égalité (=) opérateur.
  • Pour les vues matérialisées avec CUBE, ROLLUP, le regroupement d'ensembles ou leur concaténation, les restrictions suivantes s'appliquent :
    • La SELECT La liste doit contenir un distinctif de regroupement qui peut être soit un GROUPING_ID fonctionner sur tous GROUP BY expressions ou GROUPING fonctionne un pour chacun GROUP BY expression. Par exemple, si le GROUP BY La clause de la vue matérialisée est "GROUP BY CUBE(a, b)", puis le SELECT la liste doit contenir soit "GROUPING_ID(a, b)" ou "GROUPING(a) AND GROUPING(b)» pour que la vue matérialisée soit rapidement actualisable.
    • GROUP BY ne devrait pas donner lieu à des regroupements en double. Par exemple, "GROUP BY a, ROLLUP(a, b)" n'est pas actualisable rapidement car cela entraîne des regroupements en double »(a), (a, b), AND (a)«.

5.3.8.7 Restrictions sur l'actualisation rapide des vues matérialisées avec UNION ALL

Vues matérialisées avec le UNION ALL définir l'opérateur prend en charge le REFRESH FAST option si les conditions suivantes sont remplies :

  • La requête de définition doit avoir le UNION ALL opérateur au plus haut niveau.

    La UNION ALL L'opérateur ne peut pas être intégré dans une sous-requête, à une exception près : l'opérateur UNION ALL peut être dans une sous-requête dans le FROM clause à condition que la requête de définition soit de la forme SELECT * FROM (vue ou sous-requête avec UNION ALL) comme dans l'exemple suivant :

    CREATE VIEW view_with_unionall AS (SELECT c.rowid crid, c.cust_id, 2 umarker FROM clients c WHERE c.cust_last_name = 'Smith' UNION ALL SELECT c.rowid crid, c.cust_id, 3 umarker FROM clients c WHERE c.cust_last_name = 'Jones'); CRÉER UNE VUE MATÉRIALISÉE unionall_inside_view_mv RAFRAÎCHIR RAPIDEMENT À LA DEMANDE AS SELECT * FROM view_with_unionall;
    

    Notez que la vue view_with_unionall satisfait aux exigences d’un rafraîchissement rapide.

  • Chaque bloc de requête dans le UNION ALL La requête doit satisfaire aux exigences d'une vue matérialisée à actualisation rapide avec des agrégats ou d'une vue matérialisée à actualisation rapide avec des jointures.

    Les journaux de vues matérialisées appropriés doivent être créés sur les tables, comme requis pour le type correspondant de vue matérialisée à actualisation rapide.
    Notez que la base de données Oracle autorise également le cas particulier d'une vue matérialisée à table unique avec des jointures uniquement à condition que ROWID la colonne a été incluse dans la SELECT et dans le journal des vues matérialisées. Ceci est affiché dans la requête de définition de la vue view_with_unionall.

  • La SELECT la liste de chaque requête doit inclure un UNION ALL marqueur, et le UNION ALL La colonne doit avoir une valeur numérique ou de chaîne constante distincte dans chaque colonne. UNION ALL bifurquer. De plus, la colonne de marqueurs doit apparaître dans la même position ordinale dans le SELECT liste de chaque bloc de requête. Voir "Marqueur UNION ALL et réécriture de requêtes» pour plus d'informations concernant UNION ALL Marqueurs.
  • Certaines fonctionnalités telles que les jointures externes, les requêtes de vues matérialisées agrégées par insertion uniquement et les tables distantes ne sont pas prises en charge pour les vues matérialisées avec UNION ALL. Notez cependant que les vues matérialisées utilisées dans la réplication, qui ne contiennent ni jointures ni agrégats, peuvent être rapidement actualisées lorsque UNION ALL ou des tables distantes sont utilisées.
  • Le paramètre d'initialisation de compatibilité doit être défini sur 9.2.0 ou supérieur pour créer une vue matérialisée à actualisation rapide avec UNION ALL.

Je ne veux pas offenser les fans d'Oracle, mais à en juger par leur liste de restrictions, il semble que ce mécanisme n'ait pas été écrit dans le cas général, en utilisant une sorte de modèle, mais par des milliers d'Indiens, où chacun a eu la possibilité de écrire sa propre branche, et chacun d'eux a fait ce qu'il pouvait. Utiliser ce mécanisme pour une vraie logique, c’est comme traverser un champ de mines. Vous pouvez obtenir une mine à tout moment en respectant l'une des restrictions non évidentes. Son fonctionnement est également une question distincte, mais elle dépasse le cadre de cet article.

Microsoft SQL Server

Exigences supplémentaires

En plus des options SET et des exigences des fonctions déterministes, les exigences suivantes doivent être remplies :

  • L'utilisateur qui exécute CREATE INDEX doit être le propriétaire de la vue.
  • Lorsque vous créez l'index, le IGNORE_DUP_KEY L’option doit être réglée sur OFF (le paramètre par défaut).
  • Les tableaux doivent être référencés par des noms en deux parties, schéma.nom de table dans la définition de la vue.
  • Les fonctions définies par l'utilisateur référencées dans la vue doivent être créées à l'aide de l'outil WITH SCHEMABINDING option.
  • Toutes les fonctions définies par l'utilisateur référencées dans la vue doivent être référencées par des noms en deux parties, ..
  • La propriété d'accès aux données d'une fonction définie par l'utilisateur doit être NO SQL, et la propriété d'accès externe doit être NO.
  • Les fonctions CLR (Common Language Runtime) peuvent apparaître dans la liste de sélection de la vue, mais ne peuvent pas faire partie de la définition de la clé d'index clusterisé. Les fonctions CLR ne peuvent pas apparaître dans la clause WHERE de la vue ou dans la clause ON d'une opération JOIN dans la vue.
  • Les fonctions CLR et les méthodes des types définis par l'utilisateur CLR utilisées dans la définition de la vue doivent avoir les propriétés définies comme indiqué dans le tableau suivant.

    Biens immobiliers
    Notes

    DÉTERMINISTE = VRAI
    Doit être déclaré explicitement comme attribut de la méthode Microsoft .NET Framework.

    PRÉCIS = VRAI
    Doit être déclaré explicitement en tant qu'attribut de la méthode .NET Framework.

    ACCÈS AUX DONNÉES = PAS DE SQL
    Déterminé en définissant l’attribut DataAccess sur DataAccessKind.None et l’attribut SystemDataAccess sur SystemDataAccessKind.None.

    ACCÈS EXTERNE = NON
    Cette propriété a la valeur par défaut NON pour les routines CLR.

  • La vue doit être créée en utilisant le WITH SCHEMABINDING option.
  • La vue doit référencer uniquement les tables de base qui se trouvent dans la même base de données que la vue. La vue ne peut pas référencer d'autres vues.
  • L'instruction SELECT dans la définition de la vue ne doit pas contenir les éléments Transact-SQL suivants :

    COUNT
    Fonctions ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, ET OPENXML)
    OUTER rejoint (LEFT, RIGHTou FULL)

    Table dérivée (définie en spécifiant un SELECT déclaration dans le FROM clause)
    Auto-jointures
    Spécification des colonnes à l'aide de SELECT * or SELECT <table_name>.*

    DISTINCT
    STDEV, STDEVP, VAR, VARPou AVG
    Expression de table commune (CTE)

    flotter1, texte, ntext, image, XMLou flux de fichiers colonnes
    Subquery
    OVER clause, qui inclut des fonctions de classement ou de fenêtre d'agrégation

    Prédicats de texte intégral (CONTAINS, FREETEXT)
    SUM fonction qui fait référence à une expression nullable
    ORDER BY

    Fonction d'agrégation définie par l'utilisateur CLR
    TOP
    CUBE, ROLLUPou GROUPING SETS opérateurs

    MIN, MAX
    UNION, EXCEPTou INTERSECT opérateurs
    TABLESAMPLE

    Variables du tableau
    OUTER APPLY or CROSS APPLY
    PIVOT, UNPIVOT

    Ensembles de colonnes clairsemées
    Fonctions table en ligne (TVF) ou multi-instructions (MSTVF)
    OFFSET

    CHECKSUM_AGG

    1 La vue indexée peut contenir flotter Colonnes; cependant, ces colonnes ne peuvent pas être incluses dans la clé d'index clusterisé.

  • If GROUP BY est présent, la définition VIEW doit contenir COUNT_BIG(*) et ne doit pas contenir HAVING. Ces GROUP BY les restrictions s'appliquent uniquement à la définition de la vue indexée. Une requête peut utiliser une vue indexée dans son plan d'exécution même si elle ne satisfait pas à ces critères. GROUP BY restrictions.
  • Si la définition de la vue contient un GROUP BY clause, la clé de l'index clusterisé unique peut référencer uniquement les colonnes spécifiées dans la GROUP BY clause.

Il est clair ici que les Indiens n'étaient pas impliqués, puisqu'ils ont décidé de le faire selon le schéma « nous ferons peu, mais bien ». Autrement dit, ils ont plus de mines sur le terrain, mais leur emplacement est plus transparent. Le plus décevant est cette limitation :

La vue doit référencer uniquement les tables de base qui se trouvent dans la même base de données que la vue. La vue ne peut pas référencer d'autres vues.

Dans notre terminologie, cela signifie qu'une fonction ne peut pas accéder à une autre fonction matérialisée. Cela coupe dans l’œuf toute idéologie.
Aussi, cette limitation (et plus loin dans le texte) réduit considérablement les cas d'utilisation :

L'instruction SELECT dans la définition de la vue ne doit pas contenir les éléments Transact-SQL suivants :

COUNT
Fonctions ROWSET (OPENDATASOURCE, OPENQUERY, OPENROWSET, ET OPENXML)
OUTER rejoint (LEFT, RIGHTou FULL)

Table dérivée (définie en spécifiant un SELECT déclaration dans le FROM clause)
Auto-jointures
Spécification des colonnes à l'aide de SELECT * or SELECT <table_name>.*

DISTINCT
STDEV, STDEVP, VAR, VARPou AVG
Expression de table commune (CTE)

flotter1, texte, ntext, image, XMLou flux de fichiers colonnes
Subquery
OVER clause, qui inclut des fonctions de classement ou de fenêtre d'agrégation

Prédicats de texte intégral (CONTAINS, FREETEXT)
SUM fonction qui fait référence à une expression nullable
ORDER BY

Fonction d'agrégation définie par l'utilisateur CLR
TOP
CUBE, ROLLUPou GROUPING SETS opérateurs

MIN, MAX
UNION, EXCEPTou INTERSECT opérateurs
TABLESAMPLE

Variables du tableau
OUTER APPLY or CROSS APPLY
PIVOT, UNPIVOT

Ensembles de colonnes clairsemées
Fonctions table en ligne (TVF) ou multi-instructions (MSTVF)
OFFSET

CHECKSUM_AGG

OUTER JOINS, UNION, ORDER BY et autres sont interdits. Il aurait peut-être été plus facile de préciser ce qui pouvait être utilisé plutôt que ce qui ne pouvait pas l'être. La liste serait probablement beaucoup plus courte.

Pour résumer : un énorme ensemble de restrictions dans chaque SGBD (notons commercial) contre aucun (à l'exception d'une logique, non technique) dans la technologie LGPL. Cependant, il convient de noter que la mise en œuvre de ce mécanisme en logique relationnelle est un peu plus difficile que dans la logique fonctionnelle décrite.

exécution

Comment ça fonctionne? PostgreSQL est utilisé comme une « machine virtuelle ». Il existe un algorithme complexe qui crée des requêtes. Ici code source. Et il n’existe pas seulement un large éventail d’heuristiques avec un tas de si. Donc, si vous disposez de quelques mois pour étudier, vous pouvez essayer de comprendre l’architecture.

Est-ce que ça marche efficacement ? Assez efficace. Malheureusement, c'est difficile à prouver. Je peux seulement dire que si l'on considère les milliers de requêtes qui existent dans les grandes applications, elles sont en moyenne plus efficaces que celles d'un bon développeur. Un excellent programmeur SQL peut écrire n’importe quelle requête plus efficacement, mais avec mille requêtes, il n’aura tout simplement ni la motivation ni le temps pour le faire. La seule chose que je peux désormais citer comme preuve d'efficacité, c'est que plusieurs projets travaillent sur la plateforme construite sur ce SGBD. Systèmes ERP, qui ont des milliers de fonctions MATÉRIELLES différentes, avec des milliers d'utilisateurs et des bases de données de téraoctets avec des centaines de millions d'enregistrements fonctionnant sur un serveur classique à deux processeurs. Cependant, n'importe qui peut vérifier/réfuter l'efficacité en téléchargeant la plateforme et PostgreSQL, allumé enregistrer les requêtes SQL et essayer d'y modifier la logique et les données.

Dans les articles suivants, je parlerai également de la façon dont vous pouvez définir des restrictions sur les fonctions, travailler avec des sessions de modification et bien plus encore.

Source: habr.com

Ajouter un commentaire