{"id":83649,"date":"2020-06-02T07:42:21","date_gmt":"2020-06-02T05:42:21","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/database-as-sode-experience"},"modified":"2020-06-02T07:42:21","modified_gmt":"2020-06-02T05:42:21","slug":"database-as-sode-experience","status":"publish","type":"post","link":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"L'Exp\u00e9rience \u00abDatabase as Code\u00bb","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"L&#039;Exp\u00e9rience \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, que peut-il y avoir de plus simple ? Chacun d'entre nous peut \u00e9crire une requ\u00eate basique \u2014 nous tapons <strong><em>select<\/em><\/strong>, \u00e9num\u00e9rons les colonnes n\u00e9cessaires, puis <strong><em>from<\/em><\/strong>, le nom de la table, quelques conditions dans <strong><em>o\u00f9<\/em><\/strong> et voil\u00e0 \u2014 les donn\u00e9es utiles sont \u00e0 port\u00e9e de main, et ce, presque ind\u00e9pendamment de la base de donn\u00e9es utilis\u00e9e en dessous (ou peut-\u00eatre m\u00eame <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">pas une base de donn\u00e9es du tout<\/a><\/noindex>). En cons\u00e9quence, il est possible d'examiner le travail avec pratiquement n'importe quelle source de donn\u00e9es (relationnelle ou non) sous l'angle d'un simple code (avec toutes les implications \u2014 contr\u00f4le de version, relecture de code, analyse statique, tests automatis\u00e9s, et tout cela). Et cela concerne non seulement les donn\u00e9es elles-m\u00eames, les sch\u00e9mas et les migrations, mais en fait toute l'activit\u00e9 du stockage. Dans cet article, nous parlerons des t\u00e2ches quotidiennes et des probl\u00e8mes li\u00e9s \u00e0 l'utilisation de diff\u00e9rentes bases de donn\u00e9es sous l'angle de &quot;database as code&quot;.<\/p>\n<p><\/p>\n<p>Et commen\u00e7ons par <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. Les premiers affrontements du type &quot;SQL contre ORM&quot; ont \u00e9t\u00e9 observ\u00e9s d\u00e8s <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">la Russie pr\u00e9-p\u00e9troli\u00e8re<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Mapping objet-relationnel<\/h5>\n<p><\/p>\n<p>Les partisans de l'ORM appr\u00e9cient traditionnellement la rapidit\u00e9 et la simplicit\u00e9 de d\u00e9veloppement, l'ind\u00e9pendance vis-\u00e0-vis de la base de donn\u00e9es et la propret\u00e9 du code. Pour beaucoup d'entre nous, le code de travail avec la base de donn\u00e9es (et souvent la base de donn\u00e9es elle-m\u00eame)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">ressemble g\u00e9n\u00e9ralement \u00e0 peu pr\u00e8s \u00e0 ceci\u2026<\/b><\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = &quot;stock&quot;, catalog = &quot;maindb&quot;, uniqueConstraints = {\n        @UniqueConstraint(columnNames = &quot;STOCK_NAME&quot;),\n        @UniqueConstraint(columnNames = &quot;STOCK_CODE&quot;) })\npublic class Stock implements java.io.Serializable {\n\n    @Id\n    @GeneratedValue(strategy = IDENTITY)\n    @Column(name = &quot;STOCK_ID&quot;, unique = true, nullable = false)\n    public Integer getStockId() {\n        return this.stockId;\n    }\n  ...<\/code><\/pre>\n<p><\/p>\n<p>Le mod\u00e8le est agr\u00e9ment\u00e9 d'annotations intelligentes, tandis qu'en coulisses, le valeureux ORM g\u00e9n\u00e8re et ex\u00e9cute des tonnes de code SQL. \u00c0 propos, les d\u00e9veloppeurs tentent par tous les moyens de se distancer de leur base de donn\u00e9es avec des kilom\u00e8tres d'abstractions, ce qui indique une certaine <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">&quot;SQL de la haine&quot;<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>De l'autre c\u00f4t\u00e9 des barricades, les partisans du &quot;handmade&quot;-SQL soulignent la possibilit\u00e9 de tirer le meilleur parti de leur SGBD sans couches et abstractions suppl\u00e9mentaires. Ce qui donne naissance \u00e0 des projets &quot;data-centric&quot; o\u00f9 la base de donn\u00e9es est g\u00e9r\u00e9e par des personnes sp\u00e9cialement form\u00e9es (elles sont aussi appel\u00e9es &quot;data specialists&quot;, &quot;DBAs&quot;, et ainsi de suite), et les d\u00e9veloppeurs n'ont qu'\u00e0 &quot;tirer&quot; des vues et des proc\u00e9dures stock\u00e9es pr\u00eates \u00e0 l'emploi, sans entrer dans les d\u00e9tails.<\/p>\n<p><\/p>\n<p>Que se passerait-il si nous prenions le meilleur des deux mondes ? Comme c'est le cas dans cet outil remarquable au nom affermissant <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Je vais donner quelques lignes de la conception g\u00e9n\u00e9rale dans ma traduction libre, et vous pouvez vous familiariser plus en d\u00e9tail avec cela. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">ici<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure est un langage g\u00e9nial pour cr\u00e9er des DSL, mais SQL est d\u00e9j\u00e0 en soi un excellent DSL, et nous n'avons pas besoin d'un autre. Les expressions S sont super, mais ici elles n'apportent rien de nouveau. Au final, cela revient \u00e0 avoir des parenth\u00e8ses pour des parenth\u00e8ses. Pas d'accord ? Alors attendez le moment o\u00f9 l'abstraction au-dessus de la base de donn\u00e9es commencera \u00e0 fuir et vous commencerez \u00e0 lutter contre la fonction <em>(raw-sql)<\/em><\/p>\n<p>Et que faire ? Laissez SQL en tant que SQL ordinaire \u2014 un fichier pour une requ\u00eate :<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"sql\">-- name: users-by-country\nselect *\n  from users\n where country_code = :country_code<\/code><\/pre>\n<p><\/p>\n<blockquote><p>\u2026 puis lisez ce fichier, en le transformant en une fonction Clojure simple :<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries &quot;some\/where\/users_by_country.sql&quot;\n   {:connection db-spec})\n\n;;; Une fonction nomm\u00e9e `users-by-country` a \u00e9t\u00e9 cr\u00e9\u00e9e.\n;;; Utilisons-la :\n(users-by-country {:country_code &quot;GB&quot;})\n;=&gt; ({:name &quot;Kris&quot; :country_code &quot;GB&quot; ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>En respectant le principe &quot;SQL s\u00e9par\u00e9, Clojure s\u00e9par\u00e9&quot;, vous obtenez :<\/p>\n<ul>\n<li>Pas de surprises syntaxiques. Votre base de donn\u00e9es (comme toutes les autres) ne respecte pas le standard SQL \u00e0 100 % \u2014 mais pour Yesql, cela n'a pas d'importance. Vous ne perdrez jamais de temps \u00e0 chasser des fonctions ayant une syntaxe \u00e9quivalente \u00e0 SQL. Vous ne serez jamais contraint de revenir \u00e0 la fonction <em>(raw-sql &quot;some (&#8216;funky&#8217; :: SYNTAX)&quot;))<\/em>.<\/li>\n<li>Meilleure prise en charge de l'\u00e9diteur. Votre \u00e9diteur a d\u00e9j\u00e0 un excellent support SQL. En conservant SQL en tant que SQL, vous pouvez simplement l'utiliser.<\/li>\n<li>Compatibilit\u00e9 d'\u00e9quipe. Vos DBA peuvent lire et \u00e9crire SQL, que vous utilisez dans votre projet Clojure.<\/li>\n<li>Une configuration de performance plus simple. Vous devez construire un plan pour une requ\u00eate probl\u00e9matique ? Ce n'est pas un probl\u00e8me lorsque votre requ\u00eate est un SQL ordinaire.<\/li>\n<li>R\u00e9utilisation des requ\u00eates. Glissez ces m\u00eames fichiers SQL dans d'autres projets, car ce n'est qu'un vieux bon SQL \u2014 il suffit de le partager.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>\u00c0 mon avis, l'id\u00e9e est tr\u00e8s cool et en m\u00eame temps tr\u00e8s simple, ce qui a permis au projet d'avoir beaucoup de <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">suiveurs.<\/a><\/noindex> dans une grande vari\u00e9t\u00e9 de langages. Et nous essaierons ensuite d'appliquer une philosophie similaire de s\u00e9paration du code SQL de tout le reste, bien au-del\u00e0 de l'ORM.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; gestionnaires de base de donn\u00e9es<\/h5>\n<p><\/p>\n<p>Commen\u00e7ons par une t\u00e2che quotidienne simple. Nous avons souvent besoin de rechercher des objets dans une base de donn\u00e9es, par exemple, trouver une table dans un sch\u00e9ma et examiner sa structure (quelles colonnes, cl\u00e9s, index, contraintes, etc. sont utilis\u00e9s). Et de n'importe quel IDE graphique ou de tout gestionnaire de base de donn\u00e9es, nous attendons avant tout ces capacit\u00e9s. Il faut que ce soit rapide et qu'on n'ait pas \u00e0 attendre une demi-heure que la fen\u00eatre avec les informations n\u00e9cessaires s'affiche (surtout avec une connexion lente \u00e0 une base de donn\u00e9es distante), tout en garantissant que les informations obtenues soient fra\u00eeches et actuelles, et non d'anciens contenus mis en cache. Plus la base de donn\u00e9es est complexe, vaste et plus leur nombre est \u00e9lev\u00e9, plus il devient difficile d'accomplir cela.<\/p>\n<p><\/p>\n<p>Mais g\u00e9n\u00e9ralement, je mets la souris de c\u00f4t\u00e9 et je code simplement. Supposons qu'il soit n\u00e9cessaire de savoir quelles tables (et avec quelles propri\u00e9t\u00e9s) sont contenues dans le sch\u00e9ma \"HR\". Dans la plupart des SGBD, on peut obtenir le r\u00e9sultat souhait\u00e9 avec cette simple requ\u00eate depuis le information_schema :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>D'une base \u00e0 l'autre, le contenu de ces tables de r\u00e9f\u00e9rence varie en fonction des capacit\u00e9s de chaque SGBD. Par exemple, pour MySQL, \u00e0 partir de ce m\u00eame r\u00e9pertoire, nous pouvons obtenir des param\u00e8tres sp\u00e9cifiques \u00e0 ce SGBD pour la table :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Moteur utilis\u00e9 (\"MyISAM\", \"InnoDB\", etc.)\n     , row_format     -- Format de la ligne (\"Fixed\", \"Dynamic\", etc.)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle ne dispose pas d'information_schema, mais il poss\u00e8de <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">la m\u00e9tadonn\u00e9e Oracle<\/a><\/noindex>, et il n'y a pas de grands probl\u00e8mes :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- Minimum d'espace libre dans le bloc de donn\u00e9es (%)\n     , pct_used       -- Minimum d'espace utilis\u00e9 dans le bloc de donn\u00e9es (%)\n     , last_analyzed  -- Date du dernier recueil de statistiques\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>ClickHouse n'est pas une exception :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select name\n     , engine -- Moteur utilis\u00e9 (\"MergeTree\", \"Dictionary\", etc.)\n     , ...\n  from system.tables\n where database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>On peut faire quelque chose de similaire dans Cassandra (o\u00f9 il y a des columnfamilies au lieu de tables et des keyspace au lieu de sch\u00e9mas) :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- Strat\u00e9gie de compactage\n     , gc_grace_seconds           -- Dur\u00e9e de vie des d\u00e9chets\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Pour la plupart des autres bases de donn\u00e9es, on peut \u00e9galement concevoir des requ\u00eates similaires (m\u00eame dans Mongo, il existe <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">une collection syst\u00e8me sp\u00e9ciale<\/a><\/noindex>, qui contient des informations sur toutes les collections du syst\u00e8me).<\/p>\n<p><\/p>\n<p>Bien s\u00fbr, on peut obtenir des informations non seulement sur les tables, mais aussi sur n'importe quel objet. De temps en temps, des gens de bonne volont\u00e9 partagent de tels codes pour diff\u00e9rentes bases de donn\u00e9es, comme par exemple dans la s\u00e9rie d'articles de Habr intitul\u00e9e \"Fonctions pour la documentation des bases de donn\u00e9es PostgreSQL\" (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415575\">a\u00efb<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415897\">ben<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/418597\">gim<\/a><\/noindex>). \u00c9videmment, garder tous ces requ\u00eates en t\u00eate et les taper constamment est un \"plaisir\" limit\u00e9, donc dans mon IDE\/\u00e9diteur pr\u00e9f\u00e9r\u00e9, j'ai un ensemble de snippets pr\u00e9enregistr\u00e9s pour les requ\u00eates couramment utilis\u00e9es, et il ne reste plus qu'\u00e0 entrer les noms des objets dans le mod\u00e8le.<\/p>\n<p><\/p>\n<p>Ainsi, cette m\u00e9thode de navigation et de recherche d'objets est beaucoup plus flexible, \u00e9conomise beaucoup de temps et permet d'obtenir pr\u00e9cis\u00e9ment les informations dans la forme requise (comme d\u00e9crit dans le post <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Exporter des donn\u00e9es de la base de donn\u00e9es dans n'importe quel format : que savent faire les IDE sur la plateforme IntelliJ\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Op\u00e9rations sur les objets<\/h5>\n<p><\/p>\n<p>Apr\u00e8s avoir trouv\u00e9 et \u00e9tudi\u00e9 les objets n\u00e9cessaires, il est temps de faire quelque chose d'utile avec eux. Naturellement, sans quitter le clavier.<\/p>\n<p><\/p>\n<p>Il n'est pas secret qu'il suffit de supprimer une table pour que cela ressemble presque pareil dans toutes les bases de donn\u00e9es :<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>La cr\u00e9ation d'une table est d\u00e9j\u00e0 plus int\u00e9ressante. Pratiquement tous les SGBD (y compris de nombreux NoSQL) savent faire du \"create table\" d'une mani\u00e8re ou d'une autre, et la plupart des \u00e9l\u00e9ments resteront peu diff\u00e9rents (nom, liste des colonnes, types de donn\u00e9es). Cependant, d'autres d\u00e9tails peuvent varier consid\u00e9rablement et d\u00e9pendre de l'architecture interne et des capacit\u00e9s sp\u00e9cifiques du SGBD. Mon exemple pr\u00e9f\u00e9r\u00e9 \u2014 dans la documentation Oracle, il n'y a que des BNF \"nues\" pour la syntaxe de \"create table\". <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">qui occupent 31 pages<\/a><\/noindex>. D'autres SGBD poss\u00e8dent des fonctionnalit\u00e9s plus modestes, mais chacune d'elles a \u00e9galement de nombreuses caract\u00e9ristiques int\u00e9ressantes et uniques pour la cr\u00e9ation de tables (<noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/sql-createtable.html\">postgres<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/create-table.html\">mysql<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.cockroachlabs.com\/docs\/stable\/create-table.html#expanded\">cockroach<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.datastax.com\/en\/cql\/3.3\/cql\/cql_reference\/cqlCreateTable.html\">cassandra<\/a><\/noindex>). Il est peu probable qu'un \"assistant\" graphique d'une IDE quelconque (surtout une universelle) puisse couvrir toutes ces capacit\u00e9s, et m\u00eame s'il le pouvait, ce serait un spectacle pas pour les \u00e2mes sensibles. En revanche, un op\u00e9rateur correctement \u00e9crit et ex\u00e9cut\u00e9 au bon moment, <strong><em>create table<\/em><\/strong> permettra de b\u00e9n\u00e9ficier facilement de tout cela, rendant le stockage et l'acc\u00e8s \u00e0 vos donn\u00e9es fiables, optimaux et aussi confortables que possible.<\/p>\n<p><\/p>\n<p>De plus, de nombreux SGBD poss\u00e8dent leurs types d'objets sp\u00e9cifiques qui n'existent pas dans d'autres SGBD. En fait, nous pouvons effectuer des op\u00e9rations non seulement sur les objets de la base de donn\u00e9es, mais aussi sur le SGBD lui-m\u00eame, par exemple \"terminer\" un processus, lib\u00e9rer une certaine zone de m\u00e9moire, activer la trace, passer en mode \"lecture seule\" et bien plus encore.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Et maintenant, dessinons un peu.<\/h5>\n<p><\/p>\n<p>Une des t\u00e2ches les plus courantes consiste \u00e0 construire un diagramme avec des objets de base de donn\u00e9es, afin de visualiser sur une belle image les objets et les relations entre eux. Pratiquement toutes les IDE graphiques, des utilitaires en ligne de commande s\u00e9par\u00e9s, des outils graphiques sp\u00e9cialis\u00e9s et des modeleurs peuvent le faire. Ils vous dessineront quelque chose \"comme ils le peuvent\", et il n'est possible d'influer un peu sur ce processus qu'avec quelques param\u00e8tres dans le fichier de configuration ou des cases \u00e0 cocher dans l'interface.<\/p>\n<p><\/p>\n<p>Mais ce probl\u00e8me peut \u00eatre r\u00e9solu de mani\u00e8re beaucoup plus simple, flexible et \u00e9l\u00e9gante, bien s\u00fbr, \u00e0 l'aide de code. Pour construire des diagrammes de toute complexit\u00e9, nous disposons de plusieurs langages de balisage sp\u00e9cialis\u00e9s (DOT, GraphML, etc.), accompagn\u00e9s d'une multitude d'applications (GraphViz, PlantUML, Mermaid), qui peuvent lire de telles instructions et les visualiser dans divers formats. Et nous savons d\u00e9j\u00e0 comment obtenir des informations sur les objets et les liaisons entre eux.<\/p>\n<p><\/p>\n<p>Prenons un petit exemple de ce \u00e0 quoi cela pourrait ressembler, en utilisant PlantUML et <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">une base de donn\u00e9es de d\u00e9monstration pour PostgreSQL.<\/a><\/noindex> (\u00e0 gauche, la requ\u00eate SQL qui g\u00e9n\u00e9rera l'instruction n\u00e9cessaire pour PlantUML, et \u00e0 droite, le r\u00e9sultat :)<\/p>\n<p>\n<img decoding=\"async\" alt=\"L&#039;Exp\u00e9rience \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/c5cb2a138df1527abe47cbf8d695cb36.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<pre><code class=\"sql\">select '@startuml'||chr(10)||'hide methods'||chr(10)||'hide stereotypes' union all\nselect distinct ccu.table_name || ' --|&gt; ' ||\n       tc.table_name as val\n  from table_constraints as tc\n  join key_column_usage as kcu\n    on tc.constraint_name = kcu.constraint_name\n  join constraint_column_usage as ccu\n    on ccu.constraint_name = tc.constraint_name\n where tc.constraint_type = 'FOREIGN KEY'\n   and tc.table_name ~ '.*' union all\nselect '@enduml'<\/code><\/pre>\n<p><\/p>\n<p>Et si l'on s'applique un peu, on peut obtenir quelque chose de tr\u00e8s proche d'un vrai diagramme ER bas\u00e9 sur <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">un mod\u00e8le ER pour PlantUML.<\/a><\/noindex> Il est possible d'obtenir quelque chose de fortement similaire \u00e0 un v\u00e9ritable diagramme ER.<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">Une requ\u00eate SQL un peu plus compliqu\u00e9e.<\/b><\/p>\n<pre><code class=\"sql\">-- En-t&ecirc;te\nselect &#039;@startuml\n        !define Table(name,desc) class name as &quot;desc&quot; &lt;&lt; (T,#FFAAAA) &gt;&amp;gt;\n        !define primary_key(x) &lt;b&gt;x&lt;\/b&gt;\n        !define unique(x) &lt;color:green&gt;x&lt;\/color&gt;\n        !define not_null(x) &lt;u&gt;x&lt;\/u&gt;\n        hide methods\n        hide stereotypes&#039;\n union all\n-- Tables\nselect format(&#039;Table(%s, &quot;%s n information about %s&quot;) {&#039;||chr(10), table_name, table_name, table_name) ||\n       (select string_agg(column_name || &#039; &#039; || upper(udt_name), chr(10))\n          from information_schema.columns\n         where table_schema = &#039;public&#039;\n           and table_name = t.table_name) || chr(10) || &#039;}&#039;\n  from information_schema.tables t\n where table_schema = &#039;public&#039;\n union all\n-- Relations entre les tables\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;Un %s peut avoir plusieurs %s&quot;&#039;, ccu.table_name, tc.table_name)\n  from information_schema.table_constraints as tc\n  join information_schema.key_column_usage as kcu on tc.constraint_name = kcu.constraint_name\n  join information_schema.constraint_column_usage as ccu on ccu.constraint_name = tc.constraint_name\n where tc.constraint_type = &#039;FOREIGN KEY&#039;\n   and ccu.constraint_schema = &#039;public&#039;\n   and tc.table_name ~ &#039;.*&#039;\n union all\n-- Pied de page\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"L&#039;Exp\u00e9rience \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Si l'on regarde de pr\u00e8s, de nombreux outils de visualisation utilisent \u00e9galement des requ\u00eates similaires. Cependant, ces requ\u00eates sont g\u00e9n\u00e9ralement profond\u00e9ment <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">\"envelopp\u00e9s\" dans le code de l'application elle-m\u00eame et difficiles \u00e0 comprendre.<\/a><\/noindex>, sans parler de leur modification.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">M\u00e9triques et surveillance.<\/h5>\n<p><\/p>\n<p>Passons \u00e0 un sujet traditionnellement complexe : le monitoring des performances des bases de donn\u00e9es. Je vais \u00e9voquer une petite histoire vraie racont\u00e9e par \"un de mes amis\". Dans un projet, il \u00e9tait une fois un DBA puissant, et peu de d\u00e9veloppeurs le connaissaient personnellement, et encore moins l\u2019avaient vu en chair et en os (bien qu'il travaill\u00e2t, selon les rumeurs, quelque part dans le b\u00e2timent voisin). \u00c0 l'heure \"X\", lorsque le syst\u00e8me de production d'un grand d\u00e9taillant commen\u00e7ait \u00e0 nouveau \u00e0 \"aller mal\", il envoyait silencieusement des captures d'\u00e9cran des graphiques de l'Oracle Enterprise Manager, sur lesquels il mettait soigneusement en \u00e9vidence les points critiques avec un marqueur rouge pour \"plus de clart\u00e9\" (ce qui, pour le dire franchement, n'aidait pas beaucoup). Et c'est en se basant sur cette \"photo\" qu'il fallait traiter les probl\u00e8mes. Cependant, personne n'avait acc\u00e8s au pr\u00e9cieux (dans les deux sens du terme) Enterprise Manager, car le syst\u00e8me est complexe et co\u00fbteux, et les d\u00e9veloppeurs pourraient \"casser quelque chose en touchant \u00e0 \u00e7a\". Par cons\u00e9quent, les d\u00e9veloppeurs trouvaient par des m\u00e9thodes \"empiriques\" le lieu et la cause des ralentissements et publiaient un correctif. Si une lettre mena\u00e7ante du DBA ne revenait pas \u00e0 nouveau dans un proche avenir, tout le monde poussait un soupir de soulagement et revenait \u00e0 ses t\u00e2ches actuelles (jusqu'\u00e0 la nouvelle Lettre).<\/p>\n<p><\/p>\n<p>Mais le processus de monitoring peut \u00eatre plus amusant et amical, et surtout \u2014 accessible et transparent pour tous. Au moins la partie de base, en compl\u00e9ment des syst\u00e8mes de surveillance principaux (qui sont sans aucun doute utiles et indispensables dans de nombreux cas). Toute base de donn\u00e9es peut librement et compl\u00e8tement gratuitement partager des informations sur son \u00e9tat actuel et ses performances. Dans la m\u00eame \"terrible\" base de donn\u00e9es Oracle, presque toutes les informations sur les performances peuvent \u00eatre obtenues \u00e0 partir des vues syst\u00e8me, allant des processus et des sessions \u00e0 l'\u00e9tat du cache m\u00e9moire (par exemple, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">Scripts DBA<\/a><\/noindex>, section \"Monitoring\"). En Postgresql, il existe \u00e9galement toute une vari\u00e9t\u00e9 de vues syst\u00e8me pour <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">la surveillance des bases de donn\u00e9es<\/a><\/noindex>, y compris des vues essentielles pour la vie quotidienne de tout DBA, telles que <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-ACTIVITY-VIEW\">pg_stat_activity<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-DATABASE-VIEW\">pg_stat_database<\/a><\/noindex>, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html#PG-STAT-BGWRITER-VIEW\">pg_stat_bgwriter<\/a><\/noindex>. Dans MySQL, il existe m\u00eame un sch\u00e9ma distinct <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. Et dans Mongo, un <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profilleur<\/a><\/noindex> agr\u00e8ge les donn\u00e9es de performance dans une collection syst\u00e8me <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/#view-profiler-data\">system.profile<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Ainsi, en utilisant un collecteur de m\u00e9triques (Telegraf, Metricbeat, Collectd) capable d'ex\u00e9cuter des requ\u00eates SQL personnalis\u00e9es, un stockage de ces m\u00e9triques (InfluxDB, Elasticsearch, Timescaledb) et un visualiseur (Grafana, Kibana), on peut obtenir un syst\u00e8me de surveillance assez l\u00e9ger et flexible, qui s'int\u00e9grera \u00e9troitement avec d'autres m\u00e9triques syst\u00e8me g\u00e9n\u00e9rales (obtenues, par exemple, \u00e0 partir du serveur d'applications, du syst\u00e8me d'exploitation, etc.). C'est, par exemple, ce qui est r\u00e9alis\u00e9 dans pgwatch2, o\u00f9 une combinaison InfluxDB + Grafana et un ensemble de requ\u00eates aux vues syst\u00e9miques sont utilis\u00e9s, auxquels on peut \u00e9galement <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">ajouter des requ\u00eates personnalis\u00e9es<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Au total<\/h2>\n<p><\/p>\n<p>Et c\u2019est seulement une liste approximative de ce que l\u2019on peut faire avec notre base de donn\u00e9es en utilisant du code SQL standard. Je suis s\u00fbr qu'il existe de nombreuses autres applications, n'h\u00e9sitez pas \u00e0 les partager dans les commentaires. Quant \u00e0 comment (et surtout pourquoi) automatiser tout cela et l'int\u00e9grer dans votre pipeline CI\/CD, nous en parlerons la prochaine fois.<\/p>\n<p>Source : <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/426833\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435? \u041a\u0430\u0436\u0434\u044b\u0439 \u0438\u0437 \u043d\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u043d\u044c\u043a\u0438\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u2014 \u043d\u0430\u0431\u0438\u0440\u0430\u0435\u043c select, \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043b\u043e\u043d\u043a\u0438, \u0437\u0430\u0442\u0435\u043c from, \u0438\u043c\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0443\u0441\u043b\u043e\u0432\u0438\u0439 \u0432 where \u0438 \u0432\u0441\u0435 \u2014 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0443 \u043d\u0430\u0441 \u0432 \u043a\u0430\u0440\u043c\u0430\u043d\u0435, \u043f\u0440\u0438\u0447\u0435\u043c (\u043f\u043e\u0447\u0442\u0438) \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0442\u043e\u0433\u043e \u043a\u0430\u043a\u0430\u044f \u0421\u0423\u0411\u0414 \u0432 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e\u0434 \u043a\u0430\u043f\u043e\u0442\u043e\u043c (\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438 \u043d\u0435 \u0421\u0423\u0411\u0414 \u0432\u043e\u0432\u0441\u0435). \u0412 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":83650,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-83649","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2 - aioseo.com -->\n\t<meta name=\"description\" content=\"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435?\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"fr_FR\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u00abDatabase as \u0421ode\u00bb Experience | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435?\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-06-02T05:42:21+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-06-02T05:42:21+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47\u00ab Database as Code \u00bb Experience | ProHoster","description":"SQL, quoi de plus simple ?","canonical_url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"fr_FR","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u00abDatabase as \u0421ode\u00bb Experience | ProHoster","og:description":"SQL, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0449\u0435?","og:url":"https:\/\/prohoster.info\/fr\/blog\/administrirovanie\/database-as-sode-experience","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-06-02T05:42:21+00:00","article:modified_time":"2020-06-02T05:42:21+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"83649","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:13:28","updated":"2022-10-02 10:23:46","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/fr\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}