{"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\/it\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"Esperienza 'Database as Code'","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Esperienza &#039;Database as Code&#039;\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, cosa pu\u00f2 essere pi\u00f9 semplice? Ognuno di noi pu\u00f2 scrivere una semplice query \u2014 digitando <strong><em>select<\/em><\/strong>, elencando le colonne necessarie, poi <strong><em>da<\/em><\/strong>, il nome della tabella, qualche condizione in <strong><em>where<\/em><\/strong> e voil\u00e0 \u2014 i dati utili sono nella nostra tasca, quasi indipendentemente dal tipo di DBMS che stiamo utilizzando nel backend (o forse non \u00e8 nemmeno un DBMS) <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">non \u00e8 affatto un DBMS<\/a><\/noindex>). Grazie a questo, il lavoro con praticamente qualsiasi fonte di dati (relazionale e non solo) pu\u00f2 essere visto da una prospettiva di codice normale (con tutte le conseguenze \u2014 controllo versione, revisione del codice, analisi statica, test automatici e tutto il resto). E questo riguarda non solo i dati stessi, gli schemi e le migrazioni, ma in generale l'intera attivit\u00e0 del repository. In questo articolo parleremo delle attivit\u00e0 quotidiane e dei problemi nel lavorare con diversi database sotto il mirino del 'database as code'.<\/p>\n<p><\/p>\n<p>E iniziamo subito con <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. I primi scontri del tipo 'SQL vs ORM' sono stati notati gi\u00e0 nel <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">Russia prerivoluzionaria<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Il mapping oggetto-relazionale<\/h5>\n<p><\/p>\n<p>I sostenitori dell'ORM tradizionalmente apprezzano la velocit\u00e0 e la semplicit\u00e0 di sviluppo, l'indipendenza dal DBMS e la pulizia del codice. Per molti di noi, il codice per lavorare con il database (e spesso anche il database stesso)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">di solito appare pi\u00f9 o meno cos\u00ec\u2026<\/b><\/p>\n<pre><code class=\"java\">@Entity\n@Table(name = \"stock\", catalog = \"maindb\", uniqueConstraints = {\n        @UniqueConstraint(columnNames = \"STOCK_NAME\"),\n        @UniqueConstraint(columnNames = \"STOCK_CODE\") })\npublic class Stock implements java.io.Serializable {\n\n    @Id\n    @GeneratedValue(strategy = IDENTITY)\n    @Column(name = \"STOCK_ID\", unique = true, nullable = false)\n    public Integer getStockId() {\n        return this.stockId;\n    }\n  ...<\/code><\/pre>\n<p><\/p>\n<p>Il modello \u00e8 ricco di annotazioni intelligenti, mentre dietro le quinte il valoroso ORM genera ed esegue tonnellate di codice SQL. A proposito, gli sviluppatori cercano in tutti i modi di isolarsi dal loro database attraverso chilometri di astrazioni, il che indica una certa <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">\"SQL dell'odio\"<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Dall'altra parte delle barricate, i sostenitori del puro 'handmade' SQL evidenziano la possibilit\u00e0 di spremere ogni goccia dalla propria SGBD senza strati e astrazioni aggiuntive. Da ci\u00f2 nascono progetti 'data-centric', in cui i database sono gestiti da persone appositamente addestrate (i cosiddetti 'db specialist', 'database experts', ecc.), mentre agli sviluppatori resta solo il compito di 'estrarre' le viste pronte e le procedure archiviate, senza entrare nei dettagli.<\/p>\n<p><\/p>\n<p>E se prendessimo il meglio di entrambi i mondi? Come \u00e8 stato fatto in questo straordinario strumento con un nome che d\u00e0 fiducia, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Riporto un paio di frasi dalla concettualizzazione generale in una mia libera traduzione, e per una panoramica pi\u00f9 dettagliata, si pu\u00f2 approfondire <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">qui<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure \u00e8 un linguaggio fantastico per creare DSL, ma SQL \u00e8 gi\u00e0 di per s\u00e9 un fantastico DSL, e non abbiamo bisogno di un altro. Le S-espressioni sono splendide, ma qui non aggiungono nulla di nuovo. In definitiva, otteniamo parentesi per il solo gusto di avere parentesi. Non siete d'accordo? Allora aspettate quel momento in cui l'astrazione sul DB inizia a perdere colpi e iniziate a combattere con la funzione. <em>(raw-sql)<\/em><\/p>\n<p>E cosa fare? Lasciamo SQL come SQL \u2014 un file per ogni query:<\/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 e poi leggi questo file, trasformandolo in una normale funzione Clojure:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries \"some\/where\/users_by_country.sql\"\n   {:connection db-spec})\n\n;;; \u00c8 stata creata una funzione chiamata `users-by-country`.\n;;; Usiamola:\n(users-by-country {:country_code \"GB\"})\n;=&gt; ({:name \"Kris\" :country_code \"GB\" ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>Seguendo il principio 'SQL separato, Clojure separato', si ottiene:<\/p>\n<ul>\n<li>Nessuna sorpresa sintattica. Il tuo database (come qualsiasi altro) non \u00e8 conforme al 100% allo standard SQL \u2014 ma per Yesql non \u00e8 un problema. Non perderai mai tempo a cercare funzioni con una sintassi equivalente a SQL. Non dovrai mai tornare alla funzione <em>(raw-sql \"some ('funky' :: SYNTAX)\")<\/em>.<\/li>\n<li>Miglior supporto dell'editor. Il tuo editor gi\u00e0 ha un ottimo supporto per SQL. Mantenendo SQL come SQL, puoi semplicemente utilizzarlo.<\/li>\n<li>Compatibilit\u00e0 con il team. I tuoi DBA possono leggere e scrivere SQL che usi nel tuo progetto Clojure.<\/li>\n<li>Impostazione delle prestazioni pi\u00f9 semplice. Devi costruire un piano per una query problematica? Non \u00e8 un problema quando la tua query \u00e8 un semplice SQL.<\/li>\n<li>Riutilizzo delle query. Puoi trascinare questi stessi file SQL in altri progetti, perch\u00e9 \u00e8 solo un vecchio buon SQL \u2014 basta condividerlo.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>A mio avviso, l'idea \u00e8 molto interessante e allo stesso tempo molto semplice, il che ha portato il progetto ad avere molti <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">seguaci<\/a><\/noindex> in diversi linguaggi. E noi cercheremo di applicare una filosofia simile di separazione del codice SQL da tutto il resto, molto oltre l'ORM.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; gestori di DB<\/h5>\n<p><\/p>\n<p>Iniziamo con un compito semplice di tutti i giorni. Spesso ci troviamo a dover cercare alcuni oggetti nel DB, ad esempio, trovare una tabella nello schema e studiare la sua struttura (quali colonne, chiavi, indici, vincoli e altro vengono utilizzati). Ci aspettiamo da qualsiasi IDE grafico o anche da un minimo DB manager, in primo luogo, queste capacit\u00e0. Dobbiamo farlo in fretta, senza dover attendere trenta minuti affinch\u00e9 si apra una finestra con le informazioni necessarie (soprattutto con una connessione lenta a un DB remoto), e inoltre, che le informazioni ottenute siano aggiornate e attuali, e non vecchie informazioni memorizzate nella cache. Infatti, pi\u00f9 complicato e grande \u00e8 il DB e maggiore \u00e8 il numero di questi, pi\u00f9 difficile diventa fare questo.<\/p>\n<p><\/p>\n<p>Ma di solito metto da parte il mouse e scrivo semplicemente codice. Supponiamo di dover scoprire quali tabelle (e con quali propriet\u00e0) sono contenute nello schema \"HR\". Nella maggior parte dei DBMS, possiamo ottenere il risultato desiderato con una semplice query dal 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>Da un database all'altro, il contenuto di tali tabelle di riferimento varia a seconda delle capacit\u00e0 di ogni DBMS. E, ad esempio, per MySQL, dallo stesso catalogo \u00e8 possibile ottenere parametri specifici per questo DBMS della tabella:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Motore utilizzato (\"MyISAM\", \"InnoDB\" etc)\n     , row_format     -- Formato della riga (\"Fixed\", \"Dynamic\" etc)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle non supporta information_schema, ma ha invece <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">metadati Oracle<\/a><\/noindex>, e non ci sono grandi problemi:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- Percentuale minima di spazio libero nel blocco dati (%)\n     , pct_used       -- Percentuale minima di spazio utilizzato nel blocco dati (%)\n     , last_analyzed  -- Data dell'ultimo raccolto di statistiche\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Non \u00e8 da meno ClickHouse:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select name\n     , engine -- Motore utilizzato (\"MergeTree\", \"Dictionary\" etc)\n     , ...\n  from system.tables\n where database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Un qualcosa di simile pu\u00f2 essere fatto anche in Cassandra (dove ci sono column families invece di tabelle e keyspace invece di schemi):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- Strategia di compattazione\n     , gc_grace_seconds           -- Tempo di vita dei dati spazzatura\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Per la maggior parte degli altri DB, \u00e8 possibile pensare a query simili (anche in Mongo c'\u00e8 <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">una collezione sistematica speciale<\/a><\/noindex>, che contiene informazioni su tutte le collezioni nel sistema).<\/p>\n<p><\/p>\n<p>Naturalmente, in questo modo possiamo ottenere informazioni non solo sulle tabelle, ma su qualsiasi oggetto. Periodicamente, persone generose condividono questo codice per diversi DB, come nella serie di articoli di Habr \"Funzioni per la documentazione dei database PostgreSQL\" (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415575\">aib<\/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>). Naturalmente, tenere a mente tutti questi comandi e digitarli continuamente \u00e8 un \"piacere\" piuttosto spiacevole, quindi nella mia IDE\/editor preferito ho un insieme di snippet gi\u00e0 pronti per le query pi\u00f9 utilizzate, e devo solo inserire i nomi degli oggetti nel modello.<\/p>\n<p><\/p>\n<p>Di conseguenza, questo modo di navigare e cercare oggetti \u00e8 molto pi\u00f9 flessibile, fa risparmiare molto tempo e consente di ottenere proprio le informazioni necessarie e nel formato richiesto (come spiegato nel post <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Esportare i dati dal DB in qualsiasi formato: cosa possono fare le IDE sulla piattaforma IntelliJ\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Operazioni con gli oggetti<\/h5>\n<p><\/p>\n<p>Dopo aver trovato e studiato gli oggetti necessari, \u00e8 il momento di fare qualcosa di utile con essi. Naturalmente, senza staccare le dita dalla tastiera.<\/p>\n<p><\/p>\n<p>Non \u00e8 un segreto che la semplice eliminazione di una tabella appare praticamente identica in quasi tutti i DB:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>La creazione di una tabella \u00e8 gi\u00e0 un argomento pi\u00f9 interessante. Praticamente qualsiasi RDBMS (compresi molti NoSQL) ha, in un modo o nell'altro, la capacit\u00e0 di 'creare una tabella', e la sua parte principale non differisce molto (nome, elenco delle colonne, tipi di dati), ma gli altri dettagli possono variare notevolmente e dipendono dalla struttura interna e dalle capacit\u00e0 specifiche di ciascun RDBMS. Il mio esempio preferito \u00e8 che nella documentazione di Oracle ci sono solo i 'nudi' BNF per la sintassi 'crea tabella' <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">occupano 31 pagine<\/a><\/noindex>. Altri DBMS hanno funzionalit\u00e0 pi\u00f9 modeste, ma ognuno di essi ha anche molte caratteristiche interessanti e uniche per la creazione di tabelle (<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>). \u00c8 poco probabile che qualche 'wizard' grafico da un IDE qualsiasi (soprattutto se generico) possa coprire completamente tutte queste capacit\u00e0, e se lo fa, sar\u00e0 uno spettacolo non per deboli di cuore. Allo stesso tempo, un'istruzione scritta correttamente e in tempo <strong><em>create table<\/em><\/strong> permetter\u00e0 di sfruttare facilmente tutte queste funzionalit\u00e0, rendendo l'archiviazione e l'accesso ai vostri dati affidabili, ottimali e il pi\u00f9 confortevoli possibile.<\/p>\n<p><\/p>\n<p>Inoltre, molti RDBMS hanno i propri tipi di oggetti specifici che non esistono in altri RDBMS. Inoltre, possiamo eseguire operazioni non solo sugli oggetti del database, ma anche sullo stesso RDBMS, ad esempio 'terminare' un processo, liberare una certa area di memoria, abilitare il tracciamento, passare in modalit\u00e0 'sola lettura' e molto altro.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Ora facciamo un po' di disegno<\/h5>\n<p><\/p>\n<p>Una delle attivit\u00e0 pi\u00f9 comuni \u00e8 costruire un diagramma con gli oggetti del database, per vedere in un'immagine bella gli oggetti e le relazioni tra di essi. Questo \u00e8 qualcosa che qualsiasi IDE grafico, alcune utilit\u00e0 'da linea di comando', strumenti grafici specializzati e modellatori possono fare. Questi vi creeranno qualcosa 'come sanno fare', e sar\u00e0 possibile influenzare questo processo solo attraverso alcuni parametri nel file di configurazione o spuntando opzioni nell'interfaccia.<\/p>\n<p><\/p>\n<p>Tuttavia, questo problema pu\u00f2 essere risolto in modo molto pi\u00f9 semplice, flessibile ed elegante, e naturalmente con l'uso di codice. Per costruire diagrammi di qualsiasi complessit\u00e0, abbiamo immediatamente diversi linguaggi di markup specializzati (DOT, GraphML, ecc.), e a essi si affiancano numerose applicazioni (GraphViz, PlantUML, Mermaid), che possono leggere tali istruzioni e visualizzarle in vari formati. Gi\u00e0 sappiamo come ottenere le informazioni sugli oggetti e sulle relazioni tra di essi.<\/p>\n<p><\/p>\n<p>Facciamo un piccolo esempio di come potrebbe apparire, utilizzando PlantUML e <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">un database dimostrativo per PostgreSQL<\/a><\/noindex> (a sinistra la query SQL che generer\u00e0 l'istruzione necessaria per PlantUML, a destra il risultato):<\/p>\n<p>\n<img decoding=\"async\" alt=\"Esperienza &#039;Database as Code&#039;\" 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>E se si presta un po' di attenzione, sulla base <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">del template ER per PlantUML<\/a><\/noindex> si pu\u00f2 ottenere qualcosa di molto simile a un vero diagramma ER:<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">La query SQL \u00e8 un po' pi\u00f9 complessa<\/b><\/p>\n<pre><code class=\"sql\">-- Intestazione\nselect &#039;@startuml\n        !define Table(nome,desc) class nome 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-- Tabelle\nselect format(&#039;Table(%s, &quot;%s n informazioni su %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-- Relazioni tra le tabelle\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;A %s pu&ograve; avere molti %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-- Feed\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Esperienza &#039;Database as Code&#039;\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Se si guarda attentamente, si vedr\u00e0 che molti strumenti di visualizzazione utilizzano query simili. Tuttavia, queste query sono solitamente profondamente <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">'incorporati' nel codice dell'applicazione stessa e difficili da comprendere<\/a><\/noindex>, per non parlare di qualsiasi modifica.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">Metriche e monitoraggio<\/h5>\n<p><\/p>\n<p>Passiamo a un argomento tradizionalmente difficile: il monitoraggio delle performance dei database. Ricordo una piccola storia vera che mi ha raccontato \"un mio amico\". In un progetto recente c'era un potente DBA, e pochi sviluppatori lo conoscevano personalmente, tantomeno lo avevano mai visto di persona (nonostante si dicesse che lavorasse da qualche parte nell'edificio accanto). All'ora \"X\", quando il sistema di produzione di un grande rivenditore iniziava a \"star male\" ancora una volta, lui inviava silenziosamente degli screenshot dai grafici dell'Oracle Enterprise Manager, evidenziando in rosso i punti critici per una \"migliore comprensione\" (il che, per dirla con garbo, aiutava poco). Cos\u00ec si doveva \"curare\" tutto basandosi su questa \"foto\". Nel frattempo, nessuno aveva accesso all'Enterprise Manager, prezioso (in entrambi i sensi) e costoso, perch\u00e9 il sistema \u00e8 complesso e caro; chiss\u00e0, se gli sviluppatori avessero toccato qualcosa, avrebbero rovinato tutto. Pertanto, gli sviluppatori trovavano il problema e la causa dei rallentamenti in modo \"empirico\" e rilasciavano una patch. Se una lettera minacciosa del DBA non arrivava nuovamente nel breve periodo, tutti tiravano un respiro di sollievo e tornavano ai loro compiti in corso (fino alla nuova lettera).<\/p>\n<p><\/p>\n<p>Tuttavia, il processo di monitoraggio pu\u00f2 apparire pi\u00f9 vivace e amichevole, e soprattutto \u2014 disponibile e trasparente per tutti. Almeno una parte di base di esso, come integrazione ai principali sistemi di monitoraggio (che sono sicuramente utili e in molti casi insostituibili). Qualsiasi DBMS \u00e8 pronto a condividere liberamente e gratuitamente informazioni sul proprio stato attuale e sulle performance. Nella stessa \"teste di morte\" Oracle DB, praticamente qualsiasi informazione sulle performance pu\u00f2 essere ottenuta dalle viste di sistema, iniziando dai processi e sessioni fino allo stato della cache del buffer (ad esempio, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">Script DBA<\/a><\/noindex>sezione \"Monitoring\"). In PostgreSQL c'\u00e8 anche un'intera serie di viste di sistema per <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">il monitoraggio del lavoro del database<\/a><\/noindex>, in particolare quelle indispensabili nella vita quotidiana di qualsiasi DBA, come <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>. In MySQL \u00e8 stata persino creata una specifica schema <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. In Mongo, il <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profilatore<\/a><\/noindex> aggregando dati sulle prestazioni in una collezione di sistema <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>Pertanto, armati di un qualsiasi raccoglitore di metriche (Telegraf, Metricbeat, Collectd), che pu\u00f2 eseguire query SQL personalizzate, di un deposito per queste metriche (InfluxDB, Elasticsearch, Timescaledb) e di un visualizzatore (Grafana, Kibana), \u00e8 possibile ottenere un sistema di monitoraggio piuttosto semplice e flessibile, che sar\u00e0 strettamente integrato con altre metriche di sistema (ottenute, ad esempio, dal server delle applicazioni, dal sistema operativo, ecc.). Come, ad esempio, \u00e8 stato fatto in pgwatch2, dove viene utilizzata la combinazione InfluxDB + Grafana e un insieme di query alle viste di sistema, a cui \u00e8 possibile anche <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">aggiungere query personalizzate<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Totale<\/h2>\n<p><\/p>\n<p>E questo \u00e8 solo un elenco approssimativo di ci\u00f2 che si pu\u00f2 fare con il nostro database tramite codice SQL standard. Sono sicuro che si possono trovare molte altre applicazioni, scrivetelo nei commenti. E parleremo di come (e, soprattutto, perch\u00e9) automatizzare tutto questo e includerlo nel proprio pipeline CI\/CD la prossima volta.<\/p>\n<p>Fonte: <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.1.1 - 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\/it\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\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\/it\/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\u00abDatabase as Code\u00bb Experience | ProHoster","description":"SQL, cosa pu\u00f2 essere pi\u00f9 semplice?","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","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\/it\/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\/it\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}