Équilibrage des Ă©critures et des lectures dans la base de donnĂ©es

Équilibrage des Ă©critures et des lectures dans la base de donnĂ©es
Dans l'article prĂ©cĂ©dent article J'ai dĂ©crit le concept et la mise en Ɠuvre d'une base de donnĂ©es basĂ©e sur des fonctions plutĂŽt que sur des tables et des champs comme dans les bases de donnĂ©es relationnelles. De nombreux exemples ont Ă©tĂ© fournis pour montrer les avantages de cette approche par rapport Ă  la classique. Beaucoup les ont jugĂ©s peu convaincants.

Dans cet article, je vais montrer comment ce concept permet d'Ă©quilibrer rapidement et facilement les Ă©critures et les lectures dans la base de donnĂ©es sans modifier la logique de fonctionnement. Une fonctionnalitĂ© similaire a Ă©tĂ© tentĂ©e dans des SGBD commerciaux modernes (en particulier, Oracle et Microsoft SQL Server). À la fin de l'article, je montrerai les rĂ©sultats obtenus, qui, pour le dire poliment, ne sont pas trĂšs concluants.

Description

Comme auparavant, pour une meilleure comprĂ©hension, je commencerai la description par des exemples. Supposons que nous devions mettre en Ɠuvre une logique qui retourne 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 DĂ©partement ‘DĂ©partement’;
name ‘DĂ©nomination’ = CHAÎNE DE DONNÉES[100] (DĂ©partement);

CLASS Employee ‘Employé’;
department ‘DĂ©partement’ = DATA Department (Employee);
salary ‘Salaire’ = DATA NUMERIC[10,2] (Employee);

countEmployees ‘Nombre d’employĂ©s’ (Department d) = 
    GROUPE SOMME 1 SI department(Employee e) = d;
salarySum ‘Salaire total’ (Department d) = 
    GROUPE SOMME salary(Employee e) SI 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 pour ce calcul, il faut parcourir l'ensemble de la table des employĂ©s, puis les regrouper par dĂ©partement. Il y aura Ă©galement un lĂ©ger ajout (en supposant que le nombre d’employĂ©s est bien plus Ă©levĂ© que le nombre de dĂ©partements) en fonction du plan choisi. O(log nombre d'employĂ©s) ou O(nombre de dĂ©partements) pour le regroupement et autres.

Il est clair que les frais généraux peuvent varier d'un SGBD à l'autre, mais la complexité ne changera pas.

Dans l'implĂ©mentation proposĂ©e, le SGBD fonctionnel gĂ©nĂ©rera une sous-requĂȘte qui calculera les valeurs nĂ©cessaires par dĂ©partement, puis effectuera un JOIN avec la table des dĂ©partements pour obtenir le nom. Cependant, pour chaque fonction lors de la dĂ©claration, il est possible de dĂ©finir un marqueur spĂ©cial MATERIALIZED. Le systĂšme crĂ©era automatiquement un champ correspondant pour chaque telle fonction. Lorsque la valeur de la fonction change, la valeur du champ changera Ă©galement dans la mĂȘme transaction. Lors de l'appel Ă  cette fonction, l'accĂšs se fera dĂ©jĂ  au champ prĂ©-calculĂ©.

En particulier, si l'on dĂ©finit MATERIALIZED pour les fonctions countEmployees et salarySum, deux champs seront ajoutĂ©s Ă  la table des dĂ©partements, dans lesquels seront stockĂ©s le nombre d'employĂ©s et leur salaire total. Chaque fois qu'il y a un changement concernant les employĂ©s, leurs salaires ou leur appartenance aux dĂ©partements, le systĂšme mettra automatiquement Ă  jour les valeurs de ces champs. La requĂȘte ci-dessus accĂ©dera directement Ă  ces champs et s'exĂ©cutera en O(nombre de dĂ©partements).

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

Exemple :

employeesCount ‘Nombre d'employĂ©s avec un salaire > N’ (DĂ©partement d, NUMERIC[10,2] N) = 
    GROUPE SOMME salaire(Employé e) SI département(e) = d ET salaire(e) > N;

Cette fonction est définie pour une infinité de valeurs du nombre N (par exemple, toute valeur négative convient). Par conséquent, il est impossible d'appliquer MATERIALIZED. Ainsi, c'est une contrainte logique et non technique (c'est-à-dire que ce n'est pas parce que nous n'avons pas pu le réaliser). En dehors de cela, aucune restriction. Il est possible d'utiliser des regroupements, des tris, AND et OR, PARTITION, des récursions, etc.

Par exemple, dans la tùche 2.2 de l'article précédent, il est possible d'appliquer MATERIALIZED sur les deux fonctions :

acheté 'Achat' (Client c, Produit p, ENTIER y) = 
    SOMME DU GROUPE sum(Détail d) SI 
        client(commande(d)) = c ET 
        produit(d) = p ET 
        extraireAnnĂ©e(date(commande(d))) = y MATÉRIALISÉ;
Ă©valuation 'Évaluation' (Client c, Produit p, ENTIER y) = 
    SOMME DE PARTITION 1 ORDRE DESC achetĂ©(c, p, y), p PAR c, y MATÉRIALISÉ;
SÉLECTIONNER contactNom(Client c), nom(Produit p) OÙ Ă©valuation(c, p, 1997) < 3;

Le systĂšme crĂ©era lui-mĂȘme une table avec des clĂ©s de type Client, Produit et INTEGER, ajoutera deux champs et mettra Ă  jour leurs valeurs lors de tout changement. Lors des appels futurs Ă  ces fonctions, aucun calcul ne sera effectuĂ©, mais les valeurs seront lues Ă  partir des champs correspondants.

À l'aide de ce mĂ©canisme, il est possible, par exemple, de se dĂ©barrasser des rĂ©cursions (CTE) dans les requĂȘtes. En particulier, considĂ©rons les groupes qui forment un arbre Ă  l'aide de la relation enfant/parent (chaque groupe a un lien vers son parent) :

parent = DATA Group (Groupe);

Dans une base de donnĂ©es fonctionnelle, la logique des rĂ©cursions peut ĂȘtre dĂ©finie comme suit :

niveau (Groupe enfant, Groupe parent) = RÉCURSION 1l SI enfant EST Groupe ET parent == enfant
                                                             ÉTAPE 2l SI parent == parent($parent);
estParent (Groupe enfant, Groupe parent) = VRAI SI niveau(enfant, parent) MATÉRIALISÉ;

Puisque la fonction isParent est marquĂ©e MATERIALIZED, une table avec deux clĂ©s (groupes) sera créée, dans laquelle le champ isParent sera vrai uniquement si la premiĂšre clĂ© est un descendant de la seconde. Le nombre d'enregistrements dans cette table sera Ă©gal au nombre de groupes multipliĂ© par la profondeur moyenne de l'arbre. Si, par exemple, il est nĂ©cessaire de calculer le nombre de descendants d'un groupe spĂ©cifique, cette fonction peut ĂȘtre utilisĂ©e :

childrenCount (Groupe g) = SOMME GROUPE 1 SI isParent(Groupe enfant, g);

Il n'y aura pas de CTE dans la requĂȘte SQL. À la place, il y aura simplement un GROUP BY.

Grùce à ce mécanisme, il est également possible de procéder facilement à la dénormalisation de la base de données si nécessaire :

CLASS Commande 'Commande';
date 'Date' = DONNÉES DATE (Commande);

CLASS OrderDetail 'Détail de la commande';
order 'Commande' = DATA Order (OrderDetail);
date 'Date' (OrderDetail d) = date(order(d)) MATERIALIZED INDEXED;

Lorsqu'il est question de la fonction date pour une ligne de commande, il y aura une lecture depuis la table des lignes de commandes pour le champ qui a un index. Lorsque la date de la commande change, le systÚme recalculera automatiquement la date dénormalisée dans la ligne.

Avantages

À quoi sert tout ce mĂ©canisme ? Dans les SGBD classiques, sans réécriture des requĂȘtes, le dĂ©veloppeur ou le DBA peuvent simplement modifier les index, dĂ©finir des statistiques et suggĂ©rer au planificateur de requĂȘtes comment les exĂ©cuter (et les HINTs ne sont disponibles que dans les SGBD commerciaux). Peu importe leurs efforts, ils ne pourront pas exĂ©cuter la premiĂšre requĂȘte de l'article en O (nombre de dĂ©partements) sans modifier les requĂȘtes et ajouter des triggers. Dans le schĂ©ma proposĂ©, au stade de dĂ©veloppement, on peut ne pas penser Ă  la structure de stockage des donnĂ©es et aux agrĂ©gations Ă  utiliser. Tout cela peut ĂȘtre modifiĂ© Ă  la volĂ©e directement en exploitation.

Dans la pratique, cela se prĂ©sente comme suit. Certaines personnes dĂ©veloppent directement la logique en fonction de la tĂąche fixĂ©e. Elles ne maĂźtrisent ni les algorithmes et leur complexitĂ©, ni les plans d'exĂ©cution, ni les types de jointures, ni aucun autre aspect technique. Ces personnes sont plutĂŽt des analystes commerciaux que des dĂ©veloppeurs. Ensuite, tout cela passe en test ou en production. La journalisation des requĂȘtes longues est activĂ©e. Lorsqu'une requĂȘte longue est dĂ©tectĂ©e, la dĂ©cision d'activer MATERIALIZED sur une certaine fonction intermĂ©diaire est prise par d'autres personnes (plus techniques — en fait des DBA). Cela ralentit lĂ©gĂšrement l'Ă©criture (car une mise Ă  jour d'un champ supplĂ©mentaire dans la transaction est nĂ©cessaire). Cependant, non seulement cette requĂȘte est considĂ©rablement accĂ©lĂ©rĂ©e, mais toutes les autres qui utilisent cette fonction le sont Ă©galement. La dĂ©cision sur la fonction Ă  matĂ©rialiser est relativement simple. Deux paramĂštres principaux : le nombre de valeurs d'entrĂ©e possibles (c'est exactement le nombre d'enregistrements qui se trouvera dans la table correspondante) et la frĂ©quence de son utilisation dans d'autres fonctions.

Analogues

Dans les SGBD commerciaux modernes, il existe des mĂ©canismes similaires : MATERIALIZED VIEW avec FAST REFRESH (Oracle) et INDEXED VIEW (Microsoft SQL Server). Dans PostgreSQL, MATERIALIZED VIEW ne peut pas ĂȘtre mise Ă  jour dans une transaction, mais seulement sur demande (avec des restrictions trĂšs strictes), donc nous ne le prenons pas en considĂ©ration. Cependant, ils prĂ©sentent 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 ordinaire. Sinon, il vous faudra réécrire toutes les autres requĂȘtes qui accĂšdent Ă  la nouvelle vue créée afin d'utiliser cette matĂ©rialisation. Ou laisser les choses telles qu'elles sont, mais cela sera au minimum inefficace si certaines donnĂ©es dĂ©jĂ  prĂ©-calculĂ©es existent, et que beaucoup de requĂȘtes ne les utilisent pas toujours, mais les recalculent.

DeuxiĂšmement, il existe un grand nombre de restrictions :

Oracle

5.3.8.4 Restrictions générales sur le rafraßchissement rapide

La requĂȘte dĂ©finissant la vue matĂ©rialisĂ©e est limitĂ©e comme suit :

  • La vue matĂ©rialisĂ©e ne doit pas contenir de rĂ©fĂ©rences Ă  des expressions non rĂ©pĂ©titives telles que SYSDATE and ROWNUM.
  • La vue matĂ©rialisĂ©e ne doit pas contenir de rĂ©fĂ©rences Ă  RAW or LONG RAW types de donnĂ©es.
  • Elle ne peut pas contenir un SELECT sous-requĂȘte de liste.
  • Elle ne peut pas contenir de fonctions analytiques (par exemple, RANK) dans la SELECT clause.
  • Elle ne peut pas rĂ©fĂ©rencer une table sur laquelle un index XMLIndex est dĂ©fini.
  • Elle ne peut pas contenir un MODEL clause.
  • Elle ne peut pas contenir un clause avec une sous-requĂȘte. Elle ne peut pas contenir de requĂȘtes imbriquĂ©es qui aient
  • ANY ALL, , ou[START WITH 
] CONNECT BY NOT soient « vrais », mais.
  • Elle ne peut pas contenir un [START WITH 
] CONNECT BY clause.
  • Il ne peut pas contenir plusieurs tables de dĂ©tail Ă  diffĂ©rents sites.
  • ACTIVER COMMIT les vues matĂ©rialisĂ©es ne peuvent pas avoir de tables de dĂ©tail distantes.
  • Les vues matĂ©rialisĂ©es imbriquĂ©es doivent avoir une jointure ou un agrĂ©gat.
  • Les vues de jointure matĂ©rialisĂ©es et les vues agrĂ©gĂ©es matĂ©rialisĂ©es avec un GROUPE PAR la clause ne peut pas sĂ©lectionner Ă  partir d'une table organisĂ©e par index.

5.3.8.5 Restrictions sur le Rafraßchissement Rapide sur les Vues Matérialisées avec Uniquement des Jointures

Les requĂȘtes dĂ©finissant des vues matĂ©rialisĂ©es avec uniquement des jointures et sans agrĂ©gats ont les restrictions suivantes sur le rafraĂźchissement rapide :

  • Toutes les restrictions de «Restrictions GĂ©nĂ©rales sur le RafraĂźchissement Rapide«.
  • Elles ne peuvent pas avoir GROUPE PAR clauses ou agrĂ©gats.
  • Les Rowids de toutes les tables dans la DE liste doivent apparaĂźtre dans la SELECT liste de la requĂȘte.
  • Les journaux de vues matĂ©rialisĂ©es doivent exister avec les rowids pour toutes les tables de base dans le DE liste de la requĂȘte.
  • Vous ne pouvez pas crĂ©er une vue matĂ©rialisĂ©e rafraĂźchissable rapidement Ă  partir de plusieurs tables avec des jointures simples qui incluent une colonne de type objet dans la SELECT dĂ©claration.

De plus, la méthode de rafraßchissement que vous choisissez ne sera pas optimalement efficace si :

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

5.3.8.6 Restrictions sur le Rafraßchissement Rapide sur les Vues Matérialisées avec Agrégats

Les requĂȘtes dĂ©finissant des vues matĂ©rialisĂ©es avec des agrĂ©gats ou des jointures ont les restrictions suivantes sur le rafraĂźchissement rapide :

Le rafraßchissement rapide est supporté pour les deux ACTIVER COMMIT and ACTIVER SUR DEMANDE vues matérialisées, cependant les restrictions suivantes s'appliquent :

  • Toutes les tables dans la vue matĂ©rialisĂ©e doivent avoir des journaux de vues matĂ©rialisĂ©es, et les journaux de vues matĂ©rialisĂ©es doivent :
    • Contenir toutes les colonnes de la table rĂ©fĂ©rencĂ©e dans la vue matĂ©rialisĂ©e.
    • SpĂ©cifiez avec ROWID and Y COMPRIS NOUVEAUX VALEURS.
    • SpĂ©cifiez la SÉQUENCE clause si la table est censĂ©e avoir un mĂ©lange d'inserts/chargements directs, de suppressions et de mises Ă  jour.

  • Seuls SOMME, COUNT, AVG, ÉCART TYPE, VARIANCE, MIN and MAX sont supportĂ©s pour le rafraĂźchissement rapide.
  • COUNT(*) doit ĂȘtre spĂ©cifiĂ©.
  • Les fonctions agrĂ©gĂ©es doivent apparaĂźtre uniquement comme la partie la plus extĂ©rieure de l'expression. C'est-Ă -dire, des agrĂ©gats tels que AVG(AVG(x)) or AVG(x)+ AVG(x) ne sont pas autorisĂ©s.
  • Pour chaque agrĂ©gat tel que AVG(expr), le correspondant COUNT(expr) doit ĂȘtre prĂ©sent. Oracle recommande que SOMME(expr) soit spĂ©cifiĂ©.
  • Si VARIANCE(expr) or ÉCART TYPE(expr) est spĂ©cifiĂ©, COUNT(expr) and SOMME(expr) doit ĂȘtre spĂ©cifiĂ©. Oracle recommande que SOMME(expr *expr) soit spĂ©cifiĂ©.
  • Le SELECT la colonne dans la requĂȘte dĂ©finissant ne peut pas ĂȘtre une expression complexe avec des colonnes provenant de plusieurs tables de base. Un possible contournement Ă  cela est d'utiliser une vue matĂ©rialisĂ©e imbriquĂ©e.
  • Le SELECT la liste doit contenir toutes GROUPE PAR les colonnes.
  • La vue matĂ©rialisĂ©e n'est pas basĂ©e sur une ou plusieurs tables distantes.
  • Si vous utilisez un CHAR type de donnĂ©es dans les colonnes filtrĂ©es d'un journal de vues matĂ©rialisĂ©es, les ensembles de caractĂšres du site maĂźtre et de la vue matĂ©rialisĂ©e doivent ĂȘtre les mĂȘmes.
  • Si la vue matĂ©rialisĂ©e a l'une des Ă©lĂ©ments suivants, alors le rafraĂźchissement rapide est supportĂ© uniquement sur des inserts DML conventionnels et des chargements directs.
    • Vues matĂ©rialisĂ©es avec MIN or MAX agrĂ©gats
    • Vues matĂ©rialisĂ©es qui ont SOMME(expr) mais pas de COUNT(expr)
    • Vues matĂ©rialisĂ©es sans COUNT(*)

    Une telle vue matérialisée est appelée une vue matérialisée insérable uniquement.

  • Une vue matĂ©rialisĂ©e avec MAX or MIN est rafraĂźchissable rapidement aprĂšs des suppressions ou des dĂ©clarations DML mixtes si elle n'a pas un OÙ clause.
    Le rafraĂźchissement rapide max/min aprĂšs des suppressions ou des DML mixtes n'a pas le mĂȘme comportement que le cas insĂ©rable uniquement. Il supprime et recompute les valeurs max/min pour les groupes affectĂ©s. Vous devez ĂȘtre conscient de son impact sur les performances.
  • Les vues matĂ©rialisĂ©es avec des vues nommĂ©es ou des sous-requĂȘtes dans la DE clause peuvent ĂȘtre rafraĂźchies rapidement Ă  condition que les vues puissent ĂȘtre entiĂšrement fusionnĂ©es. Pour des informations sur les vues qui seront fusionnĂ©es, voir RĂ©fĂ©rence du Langage SQL d'Oracle Database.
  • S'il n'y a pas de jointures externes, vous pouvez avoir des sĂ©lections et des jointures arbitraires dans le OÙ clause.
  • Les vues agrĂ©gĂ©es matĂ©rialisĂ©es avec des jointures externes sont rafraĂźchissables rapidement aprĂšs un DML conventionnel et des chargements directs, Ă  condition que seule la table externe ait Ă©tĂ© modifiĂ©e. De plus, 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 ANDet doivent utiliser l'Ă©galitĂ© (=) l'opĂ©rateur.
  • Pour les vues matĂ©rialisĂ©es avec CUBE, ROLLUP, des ensembles de regroupement, ou leur concatĂ©nation, les restrictions suivantes s'appliquent :
    • Le SELECT la liste doit contenir un identifiant de regroupement qui peut ĂȘtre soit un GROUPING_ID fonction sur toutes les GROUPE PAR expressions ou GROUPING fonctions, une pour chaque GROUPE PAR expression. Par exemple, si la GROUPE PAR clause de la vue matĂ©rialisĂ©e est «GROUPE PAR CUBE(a, b)«, alors la SELECT liste doit contenir soit «GROUPING_ID(a, b)» ou «GROUPING(a) AND GROUPING(b)» pour que la vue matĂ©rialisĂ©e soit rafraĂźchissable rapidement.
    • GROUPE PAR ne doit pas aboutir Ă  des regroupements par duplicata. Par exemple, «GROUP BY a, ROLLUP(a, b)» n'est pas rapidement rafraĂźchissable car elle aboutit Ă  des regroupements par duplicata «(a), (a, b), ET (a)«.

5.3.8.7 Restrictions sur le Rafraßchissement Rapide des Vues Matérialisées avec UNION ALL

Les vues matérialisées avec l'opérateur UNION , ou supportent l'option REFRESH FAST si les conditions suivantes sont respectées :

  • La requĂȘte dĂ©finissant doit avoir l'opĂ©rateur au niveau supĂ©rieur. UNION , ou l'opĂ©rateur ne peut pas ĂȘtre intĂ©grĂ© dans une sous-requĂȘte, exceptĂ© dans une exception : le

    Le UNION , ou peut ĂȘtre dans une sous-requĂȘte dans la UNION , ou clause Ă  condition que la requĂȘte dĂ©finissant soit de la forme DE SELECT * FROM (vue ou sous-requĂȘte avec ) comme dans l'exemple suivant : UNION , ouCREATE 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;

    Notez que la vue
    

    view_with_unionall satisfait les exigences pour un rafraĂźchissement rapide. Chaque bloc de requĂȘte dans la

  • requĂȘte doit satisfaire aux exigences d'une vue matĂ©rialisĂ©e rapidement rafraĂźchissable avec des agrĂ©gats ou d'une vue matĂ©rialisĂ©e rapidement rafraĂźchissable avec des jointures. UNION , ou Les journaux de vue matĂ©rialisĂ©e appropriĂ©s doivent ĂȘtre créés sur les tables comme requis pour le type correspondant de vue matĂ©rialisĂ©e rapidement rafraĂźchissable.

    Notez que la base de données Oracle permet également le cas particulier d'une vue matérialisée avec jointures uniquement, à condition que la
    colonne ait Ă©tĂ© incluse dans la ROWID liste et dans le journal de la vue matĂ©rialisĂ©e. Cela est montrĂ© dans la requĂȘte dĂ©finissant la vue. SELECT la liste de chaque requĂȘte doit inclure un satisfait les exigences pour un rafraĂźchissement rapide..

  • Le SELECT marqueur, et la UNION , ou colonne doit avoir une valeur numĂ©rique ou de chaĂźne constante distincte dans chaque UNION , ou branche. De plus, la colonne de marqueur doit apparaĂźtre dans la mĂȘme position ordinale dans la UNION , ou liste de chaque bloc de requĂȘte. Voir « SELECT UNION ALL Marker and Query Rewrite» pour plus d'informations concernantles marqueurs. UNION , ou Certaines fonctionnalitĂ©s, telles que les jointures externes, les requĂȘtes de vues matĂ©rialisĂ©es agrĂ©gĂ©es en mode insertion uniquement et les tables distantes ne sont pas prises en charge pour les vues matĂ©rialisĂ©es avec
  • . Notez cependant que les vues matĂ©rialisĂ©es utilisĂ©es dans la rĂ©plication, qui ne contiennent ni jointures ni agrĂ©gats, peuvent ĂȘtre rafraĂźchies rapidement lorsque UNION , ouou des tables distantes sont utilisĂ©es. UNION , ou Le paramĂštre d'initialisation de compatibilitĂ© doit ĂȘtre rĂ©glĂ© sur 9.2.0 ou plus pour crĂ©er une vue matĂ©rialisĂ©e rafraĂźchissable rapidement avec
  • Le paramĂštre d'initialisation de compatibilitĂ© doit ĂȘtre dĂ©fini sur 9.2.0 ou une version supĂ©rieure pour crĂ©er une vue matĂ©rialisĂ©e avec mise Ă  jour rapide de UNION , ou.

Je ne veux pas blesser les fans d'Oracle, mais Ă  en juger par leur liste de limitations, on a l'impression que ce mĂ©canisme n'a pas Ă©tĂ© conçu de maniĂšre gĂ©nĂ©rale, en utilisant un modĂšle, mais par des milliers d'Indiens Ă  qui on a donnĂ© la libertĂ© d'Ă©crire leur propre branche, avec chacun qui a fait ce qu'il a pu. Utiliser ce mĂ©canisme pour de la logique rĂ©elle, c'est comme marcher sur un champ de mines. À tout moment, on peut dĂ©clencher une mine en tombant sur l'une des limitations non Ă©videntes. Comment cela fonctionne, c'est une autre question, mais cela dĂ©passe le cadre de cet article.

Microsoft SQL Server

Exigences supplémentaires

En plus des options SET et des exigences de fonction dĂ©terministe, les exigences suivantes doivent ĂȘtre satisfaites :

  • L'utilisateur qui exĂ©cute CREATE INDEX doit ĂȘtre le propriĂ©taire de la vue.
  • Lorsque vous crĂ©ez l'index, l’ IGNORE_DUP_KEY l'option doit ĂȘtre dĂ©finie sur OFF (paramĂštre par dĂ©faut).
  • Les tables doivent ĂȘtre rĂ©fĂ©rencĂ©es 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 en utilisant l'option WITH SCHEMABINDING Tout fonction dĂ©finie par l'utilisateur rĂ©fĂ©rencĂ©e dans la vue doit ĂȘtre rĂ©fĂ©rencĂ©e par des noms en deux parties,
  • <schĂ©ma> <fonction>.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 ĂȘtreNON Les fonctions de runtime commun (CLR) 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 cluster. 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Ă©s dans la dĂ©finition de la vue doivent avoir les propriĂ©tĂ©s dĂ©finies comme indiquĂ© dans le tableau suivant.
  • Remarque

    Propriété
    DÉTERMINISTIQUE = VRAI

    Doit ĂȘtre dĂ©clarĂ© explicitement comme un attribut de la mĂ©thode Microsoft .NET Framework.
    PRÉCIS = VRAI

    Doit ĂȘtre dĂ©clarĂ© explicitement comme un attribut de la mĂ©thode .NET Framework.
    ACCÈS AUX DONNÉES = AUCUN SQL

    Déterminé en définissant l'attribut DataAccess sur DataAccessKind.None et l'attribut SystemDataAccess sur SystemDataAccessKind.None.
    ACCÈS EXTERNE = AUCUN

    Cette propriété par défaut est NON pour les routines CLR.
    La vue doit ĂȘtre créée en utilisant le

  • La vue doit faire uniquement rĂ©fĂ©rence aux 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. WITH SCHEMABINDING Tout fonction dĂ©finie par l'utilisateur rĂ©fĂ©rencĂ©e dans la vue doit ĂȘtre rĂ©fĂ©rencĂ©e par des noms en deux parties,
  • La dĂ©claration SELECT dans la dĂ©finition de la vue ne doit pas contenir les Ă©lĂ©ments suivants de Transact-SQL :
  • Fonctions ROWSET (

    COUNT
    OPENDATASOURCEOPENQUERY, OPENROWSET, , ETOPENXML JOINTS EXTÉRIEURS ()
    GAUCHE DROITTable dérivée (définie en spécifiant une, déclaration dans la[START WITH 
] CONNECT BY FULL)

    clause) SELECT Auto-joints DE Spécifiant des colonnes en utilisant
    SELECT *
    SELECT <nom_de_table>.* STDEV or STDEVP

    DISTINCT
    VAR, VARP, Expression de table commune (CTE), ntext[START WITH 
] CONNECT BY AVG
    XML

    float1, text, filestream, image, colonnes[START WITH 
] CONNECT BY Sous-requĂȘte CLAUSE OVER, qui inclut des fonctions de fenĂȘtre de classement ou d'agrĂ©gation
    Prédicats de recherche en texte intégral (
    CONTIENT FREETEXT

    fonction qui référence une expression nullableFonction d'agrégation définie par l'utilisateur CLR, TOP)
    SOMME ENSEMBLES DE GROUPAGE
    ORDER BY

    opérateurs
    EXCEPT
    CUBE, ROLLUP[START WITH 
] CONNECT BY ÉCHANTILLONNER Variables de table

    MIN, MAX
    UNION, OUTER APPLY[START WITH 
] CONNECT BY INTERSECT Variables de table
    PIVOT

    UNPIVOT
    Ensembles de colonnes éparses or CROSS APPLY
    Fonctions de table valorisées en ligne (TVF) ou multi-énoncé (MSTVF), CHECKSUM_AGG

    1 La vue indexée peut contenir
    colonnes ; cependant, de telles colonnes ne peuvent pas ĂȘtre incluses dans la clĂ© d'index cluster.
    OFFSET

    GROUPE PAR

    est présent, la définition de la VUE doit contenir float COUNT_BIG(*)

  • Si et ne doit pas contenir . Ces restrictions ne s'appliquent qu'Ă  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 respecte pas ces restrictions. clause avec une sous-requĂȘte.Si la dĂ©finition de la vue contient une et ne doit pas contenir clause, la clĂ© de l'index cluster unique ne peut faire rĂ©fĂ©rence qu'aux colonnes spĂ©cifiĂ©es dans le et ne doit pas contenir restrictions.
  • Si la dĂ©finition de la vue contient un et ne doit pas contenir clause, la clĂ© de l'index clusterisĂ© unique ne peut rĂ©fĂ©rencer que les colonnes spĂ©cifiĂ©es dans le et ne doit pas contenir clause.

Il est clair que les Indiens n'ont pas été attirés, car ils ont décidé de suivre le schéma "nous ferons peu, mais bien". Cela signifie qu'ils ont plus de mines sur le terrain, mais leur emplacement est plus transparent. Ce qui est le plus décevant, c'est cette restriction :

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

Dans notre terminologie, cela signifie qu'une fonction ne peut pas faire appel à une autre fonction matérialisée. Cela met à mal toute l'idéologie.
Cette restriction (et plus loin dans le texte) réduit considérablement les possibilités d'utilisation :

Fonctions ROWSET (

COUNT
OPENDATASOURCEOPENQUERY, OPENROWSET, , ETOPENXML JOINTS EXTÉRIEURS ()
GAUCHE DROITTable dérivée (définie en spécifiant une, déclaration dans la[START WITH 
] CONNECT BY FULL)

clause) SELECT Auto-joints DE Spécifiant des colonnes en utilisant
SELECT *
SELECT <nom_de_table>.* STDEV or STDEVP

DISTINCT
VAR, VARP, Expression de table commune (CTE), ntext[START WITH 
] CONNECT BY AVG
XML

float1, text, filestream, image, colonnes[START WITH 
] CONNECT BY Sous-requĂȘte CLAUSE OVER, qui inclut des fonctions de fenĂȘtre de classement ou d'agrĂ©gation
Prédicats de recherche en texte intégral (
CONTIENT FREETEXT

fonction qui référence une expression nullableFonction d'agrégation définie par l'utilisateur CLR, TOP)
SOMME ENSEMBLES DE GROUPAGE
ORDER BY

opérateurs
EXCEPT
CUBE, ROLLUP[START WITH 
] CONNECT BY ÉCHANTILLONNER Variables de table

MIN, MAX
UNION, OUTER APPLY[START WITH 
] CONNECT BY INTERSECT Variables de table
PIVOT

UNPIVOT
Ensembles de colonnes éparses or CROSS APPLY
Fonctions de table valorisées en ligne (TVF) ou multi-énoncé (MSTVF), CHECKSUM_AGG

1 La vue indexée peut contenir
colonnes ; cependant, de telles colonnes ne peuvent pas ĂȘtre incluses dans la clĂ© d'index cluster.
OFFSET

GROUPE PAR

Les OUTER JOINS, UNION, ORDER BY, et autres sont interdits. Il aurait peut-ĂȘtre Ă©tĂ© plus simple d'indiquer ce qui peut ĂȘtre utilisĂ©, plutĂŽt que ce qui ne peut pas. La liste aurait probablement Ă©tĂ© beaucoup plus courte.

En rĂ©sumĂ© : un vaste ensemble de restrictions dans chaque SGBD (je souligne commercial) vs aucune (Ă  l'exception d'une logique, pas technique) dans la technologie LGPL. Cependant, il convient de noter que la mise en Ɠuvre de ce mĂ©canisme dans une logique relationnelle est un peu plus complexe que dans la logique fonctionnelle dĂ©crite.

Mise en Ɠuvre

Comment cela fonctionne-t-il ? Comme "machine virtuelle", PostgreSQL est utilisĂ©. À l'intĂ©rieur, il y a un algorithme complexe qui s'occupe de la construction des requĂȘtes. Voici le code source. Et il n'y a pas simplement un grand nombre d'heuristiques avec une multitude de if. Donc, si vous avez quelques mois pour Ă©tudier, vous pouvez essayer de comprendre l'architecture.

Est-ce que cela fonctionne efficacement ? Assez efficacement. Malheureusement, il est difficile de le prouver. Je ne peux que dire que si l'on considĂšre des milliers de requĂȘtes dans de grandes applications, en moyenne elles sont plus efficaces que celles d'un bon dĂ©veloppeur. Un excellent programmeur SQL peut Ă©crire n'importe quelle requĂȘte de maniĂšre plus efficace, mais sur mille requĂȘtes, il n'a tout simplement ni la motivation ni le temps de le faire. La seule chose que je peux apporter comme preuve d'efficacitĂ© est que plusieurs projets fonctionnent sur une plateforme basĂ©e sur ce SGBD systĂšmes ERP, dans lesquels il y a des milliers de fonctions MATERIALIZED diffĂ©rentes, avec des milliers d'utilisateurs et des bases de donnĂ©es de tĂ©raoctets contenant des centaines de millions d'enregistrements, fonctionnant sur un serveur Ă  deux processeurs ordinaire. Cependant, quiconque le souhaite peut vĂ©rifier/rĂ©futer l'efficacitĂ© en tĂ©lĂ©chargeant la plateforme et PostgreSQL, en activant la journalisation des requĂȘtes SQL et en essayant de modifier la logique et les donnĂ©es.

Dans les articles suivants, je parlerai également de la maniÚre d'imposer des restrictions sur les fonctions, de la gestion des sessions de modifications et bien plus encore.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster