{"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 \u00abDatabase as Code\u00bb","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Esperienza \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, cosa pu\u00f2 essere pi\u00f9 semplice? Ognuno di noi pu\u00f2 scrivere una semplice query \u2014 digitiamo <strong><em>select<\/em><\/strong>, elenchiamo le colonne necessarie, poi <strong><em>from<\/em><\/strong>, il nome della tabella, qualche condizione in <strong><em>dove<\/em><\/strong> e voil\u00e0 \u2014 i dati utili sono a portata di mano, praticamente (quasi) indipendentemente dal tipo di DBMS che sta funzionando sotto il cofano (o forse non \u00e8 nemmeno <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">un DBMS)<\/a><\/noindex>). Di conseguenza, il lavoro con praticamente qualsiasi sorgente di dati (relazionale e non) pu\u00f2 essere considerato dal punto di vista del codice ordinario (con tutte le conseguenze \u2014 controllo della 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 anche tutta l'attivit\u00e0 del magazzino. In questo articolo parleremo delle attivit\u00e0 quotidiane e dei problemi legati al lavoro con diversi database sotto la lente di &quot;database as code&quot;.<\/p>\n<p><\/p>\n<p>E iniziamo proprio con <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. Le prime battaglie del tipo &quot;SQL vs ORM&quot; sono state notate gi\u00e0 nel <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">Rus' pre-petroviana<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Mapping oggetto-relazionale<\/h5>\n<p><\/p>\n<p>I sostenitori dell'ORM tradizionalmente apprezzano la velocit\u00e0 e la semplicit\u00e0 dello sviluppo, l'indipendenza dal DBMS e la pulizia del codice. Per molti di noi, il codice per l'interazione con il DB (e spesso il DB 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 = &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>Il modello \u00e8 arricchito con annotazioni intelligenti, mentre dietro le quinte un valoroso ORM genera ed esegue tonnellate di codice SQL. A proposito, gli sviluppatori si sforzano di separarsi dal loro DB con chilometri di astrazioni, il che indica una certa <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">&quot;SQL della discordia&quot;<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Dall'altra parte delle barricate, i sostenitori del puro SQL \"handmade\" sottolineano la possibilit\u00e0 di spremere il massimo dal proprio DBMS senza strati e astrazioni aggiuntive. Di conseguenza, nascono progetti \"data-centric\", dove i database sono gestiti da persone appositamente formate (chiamate anche \"database specialist\", \"database engineer\", oppure \"database admin\"), mentre agli sviluppatori resta solo il compito di \"interrogare\" le viste pronte e le procedure memorizzate, senza entrare nei dettagli.<\/p>\n<p><\/p>\n<p>E se prendessimo il meglio di entrambi i mondi? Come \u00e8 realizzato nel meraviglioso strumento dal nome incoraggiante <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Ecco un paio di frasi dall'idea generale in una mia libera traduzione, per approfondire ulteriormente il tema, si pu\u00f2 leggere di pi\u00f9. <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 di per s\u00e9 \u00e8 gi\u00e0 un ottimo DSL, e non abbiamo bisogno di un altro. Le S-espressioni sono belle, ma qui non aggiungono nulla di nuovo. Risultato: parentesi per il gusto di avere parentesi. Non sei d'accordo? Aspetta solo che l'astrazione sul DB inizi a perdere colpi, e comincerai a combattere contro le funzioni. <em>(raw-sql)<\/em><\/p>\n<p>E cosa fare? Lasciamo SQL cos\u00ec com'\u00e8 - un file per ogni richiesta:<\/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 leggete 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 con il nome `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\", ottieni:<\/p>\n<ul>\n<li>Nessuna sorpresa sintattica. Il tuo database (come qualsiasi altro) non corrisponde mai allo standard SQL al 100% \u2014 ma per Yesql questo non \u00e8 un problema. Non perderai mai tempo a cercare funzioni con una sintassi equivalente a SQL. Non dovrai mai tornare a una funzione. <em>(raw-sql \"some (\u2018funky\u2019 :: SYNTAX)\"))<\/em>.<\/li>\n<li>Il miglior supporto per l'editor. Il tuo editor ha gi\u00e0 un eccellente supporto per SQL. Mantenendo SQL come SQL, puoi semplicemente usarlo.<\/li>\n<li>Compatibilit\u00e0 di comando. I tuoi DBA possono leggere e scrivere SQL che utilizzi nel tuo progetto Clojure.<\/li>\n<li>Configurazione delle prestazioni semplificata. Hai bisogno di un piano per una query problematica? Non \u00e8 un problema quando la tua query \u00e8 un semplice SQL.<\/li>\n<li>Riutilizzo delle query. Trascina questi stessi file SQL in altri progetti, perch\u00e9 \u00e8 semplicemente un vecchio buon SQL \u2014 condividilo.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Penso che l'idea sia molto interessante e allo stesso tempo molto semplice, il che ha portato il progetto a molteplici <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">seguaci<\/a><\/noindex> in molte lingue diverse. E noi cercheremo di applicare una filosofia simile di separazione del codice SQL da tutto il resto, ben oltre l'ORM.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; DB-gestori<\/h5>\n<p><\/p>\n<p>Iniziamo con un compito semplice di routine. Spesso dobbiamo cercare oggetti nel database, ad esempio trovare una tabella in uno schema e studiarne la struttura (quali colonne, chiavi, indici, vincoli e cos\u00ec via vengono utilizzati). Da qualsiasi IDE grafica o da un qualsiasi DB-manager ci aspettiamo, prima di tutto, queste capacit\u00e0. Deve essere veloce e non dobbiamo aspettare mezz'ora affinch\u00e9 appaia una finestra con le informazioni necessarie (soprattutto con una connessione lenta a un database remoto), e inoltre, le informazioni ottenute devono essere aggiornate e attuali, non un vecchio dato memorizzato nella cache. Infatti, pi\u00f9 complesso e grande \u00e8 il database e maggiore \u00e8 il numero degli stessi, pi\u00f9 difficile diventa ottenere queste informazioni.<\/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 dall'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>Dalla base alla base, il contenuto di tali tabelle di riferimento varia a seconda delle capacit\u00e0 di ciascun DBMS. Ad esempio, per MySQL, da questo stesso riferimento \u00e8 possibile ottenere parametri specifici per questo DBMS:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Motore utilizzato (\"MyISAM\", \"InnoDB\" ecc.)\n     , row_format     -- Formato della riga (\"Fixed\", \"Dynamic\" ecc.)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle non supporta information_schema, ma ha <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       -- Minimo spazio libero nel blocco dati (%)\n     , pct_used       -- Minimo spazio utilizzato nel blocco dati (%)\n     , last_analyzed  -- Data dell'ultimo raccolto statistico\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Non fa eccezione ClickHouse:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">seleziona nome\n     , motore -- Il motore utilizzato (&quot;MergeTree&quot;, &quot;Dictionary&quot; ecc.)\n     , ...\n  da system.tables\n dove database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Qualcosa di simile si pu\u00f2 fare anche in Cassandra (dove ci sono columnfamilies al posto di tabelle e keyspace&#8217; per gli schemi):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- Strategia di raccolta spazzatura\n     , gc_grace_seconds           -- Tempo di vita della 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 ideare 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 di sistema speciale<\/a><\/noindex>, che contiene informazioni su tutte le collezioni nel sistema).<\/p>\n<p><\/p>\n<p>Ovviamente, in questo modo \u00e8 possibile ottenere informazioni non solo sulle tabelle, ma su qualsiasi oggetto. Periodicamente, persone gentili condividono questo codice per diversi DB, come, ad esempio, nella serie di articoli su Habr &quot;Funzioni per la documentazione delle basi di dati PostgreSQL&quot; (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/post\/415575\">ib<\/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\">gym<\/a><\/noindex>). Certamente, tenere a mente tutta questa montagna di query e digitarle costantemente \u00e8 un divertimento &quot;cos\u00ec cos\u00ec&quot;, quindi nella mia IDE\/editor preferita ho un set di snippet preimpostati per le query pi\u00f9 comuni 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, risparmia molto tempo e consente di ottenere le informazioni esattamente nel formato di cui abbiamo bisogno (come descritto nel post <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">&quot;Esportazione dei dati da DB in qualsiasi formato: cosa possono fare le IDE sulla piattaforma IntelliJ&quot;<\/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 tempo di fare qualcosa di utile con loro. Naturalmente, senza staccare le dita dalla tastiera.<\/p>\n<p><\/p>\n<p>Non \u00e8 un segreto che la semplice rimozione di una tabella appaia quasi identica in tutti i DB:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>Ma la creazione di una tabella \u00e8 gi\u00e0 pi\u00f9 interessante. Praticamente ogni DBMS (compresi molti NoSQL) sa in un modo o nell'altro eseguire un &quot;create table&quot;, e la sua parte principale differir\u00e0 poco (nome, elenco delle colonne, tipi di dati), ma gli altri dettagli possono variare notevolmente e dipendono dalla struttura interna e dalle capacit\u00e0 del specifico DBMS. Il mio esempio preferito \u00e8 che nella documentazione di Oracle ci sono solo delle BNF 'nude' per la sintassi di &quot;create table&quot; <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 limitate, 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 &quot;wizard&quot; grafico di qualche IDE (specialmente se universale) possa coprire completamente tutte queste capacit\u00e0, e se anche lo fa, sar\u00e0 uno spettacolo non per i deboli di cuore. Allo stesso tempo, un'istruzione scritta correttamente e tempestivamente <strong><em>create table<\/em><\/strong> permetter\u00e0 di sfruttare senza sforzo tutte queste funzionalit\u00e0, rendendo l'archiviazione e l'accesso ai tuoi dati sicuri, ottimali e il pi\u00f9 confortevoli possibile.<\/p>\n<p><\/p>\n<p>Inoltre, molti DBMS hanno i loro tipi di oggetti specifici, che sono assenti in altri DBMS. Dobbiamo anche eseguire operazioni non solo sugli oggetti del database, ma anche sullo stesso DBMS, ad esempio &quot;terminare&quot; un processo, liberare una certa area di memoria, attivare il tracing, passare alla modalit\u00e0 &quot;read only&quot; e molto altro.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Adesso un po' di disegno<\/h5>\n<p><\/p>\n<p>Una delle esigenze pi\u00f9 comuni \u00e8 costruire un diagramma con gli oggetti del database, per vedere in un'immagine gradevole gli oggetti e le relazioni tra di essi. Questo \u00e8 qualcosa che quasi tutte le IDE grafiche, alcune utilit\u00e0 da riga di comando, strumenti grafici specializzati e modelli possono fare. Questi strumenti disegnano qualcosa \"come possono\", e l'unico modo per influenzare questo processo \u00e8 attraverso alcuni parametri nel file di configurazione o opzioni nell'interfaccia.<\/p>\n<p><\/p>\n<p>Ma questo problema pu\u00f2 essere risolto in modo molto pi\u00f9 semplice, flessibile ed elegante, e ovviamente con l'ausilio del codice. Per la creazione di diagrammi di qualsiasi complessit\u00e0, abbiamo a disposizione diversi linguaggi di markup specializzati (DOT, GraphML, ecc.), e una miriade di applicazioni (GraphViz, PlantUML, Mermaid) capaci di leggere tali istruzioni e visualizzarle in vari formati. Inoltre, gi\u00e0 sappiamo come ottenere informazioni sugli oggetti e le relazioni tra di essi.<\/p>\n<p><\/p>\n<p>Facciamo un breve 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 la necessaria istruzione per PlantUML, e a destra il risultato):<\/p>\n<p>\n<img decoding=\"async\" alt=\"Esperienza \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>E se ci si impegna un po', sulla base del <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">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(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-- 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 tabelle\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;Una %s pu&ograve; avere molte %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-- Fondo\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"Esperienza \u00abDatabase as Code\u00bb\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Se si guarda attentamente, molti strumenti di visualizzazione utilizzano richieste simili nello stesso modo. Tuttavia, queste richieste sono spesso \"incorporate\" nel codice stesso dell'applicazione e sono difficili da comprendere <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">\"incapsulati\" nel codice stesso dell'applicazione e difficili da comprendere<\/a><\/noindex>Metriche e monitoraggio<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">Metriche e monitoraggio<\/h5>\n<p><\/p>\n<p>Affrontiamo un argomento tradizionalmente complesso: il monitoraggio delle prestazioni del database. Ricordo una piccola storia vera raccontata da \"un mio amico\". In un certo progetto, c'era un potente DBA, e pochi sviluppatori lo conoscevano personalmente, e in realt\u00e0 molti di loro non lo avevano mai visto di persona (anche se, secondo le voci, lavorava da qualche parte nel vicino edificio). All'ora \"X\", quando il sistema di produzione di un grande rivenditore iniziava a \"star male\" per l'ennesima volta, lui silenziosamente inviava screenshot dei grafici dall'Oracle Enterprise Manager, evidenziando con un evidenziatore rosso i punti critici per \"chiarezza\" (eufemisticamente parlando, questo aiutava poco). E cos\u00ec si doveva curare secondo questa \"fotografia\". Nel contempo, nessuno aveva accesso al prezioso (in entrambi i sensi della parola) Enterprise Manager, poich\u00e9 il sistema era complesso e costoso, e si temeva che gli sviluppatori potessero \"sbagliare e rompere tutto\". Pertanto, gli sviluppatori trovavano il luogo e la causa dei rallentamenti in modo \"empirico\" e rilasciavano una patch. Se una lettera minacciosa del DBA non arrivava nuovamente entro breve, tutti tiravano un sospiro di sollievo e tornavano ai propri compiti attuali (fino a una nuova Lettera).<\/p>\n<p><\/p>\n<p>Ma il processo di monitoraggio pu\u00f2 apparire pi\u00f9 interessante e amichevole, e soprattutto \u2014 accessibile e trasparente per tutti. Almeno la sua parte fondamentale, come aggiunta ai sistemi di monitoraggio principali (che sono sicuramente utili e, in molti casi, indispensabili). Qualsiasi DBMS \u00e8 pronto a condividere liberamente e gratuitamente informazioni sul proprio stato e sulle prestazioni attuali. Nella stessa Oracle DB 'cruenta', \u00e8 possibile ottenere praticamente tutte le informazioni sulle prestazioni dalle viste di sistema, a partire dai processi e dalle sessioni e fino allo stato della cache dei buffer (ad esempio, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">DBA Scripts<\/a><\/noindex>, sezione 'Monitoring'). In Postgresql ci sono anche una serie di viste di sistema per <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">il monitoraggio delle prestazioni del DB<\/a><\/noindex>, in particolare alcune indispensabili nella vita quotidiana di ogni 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, c'\u00e8 addirittura uno schema dedicato <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. E in Mongo, un <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profilatore<\/a><\/noindex> aggregato dei dati sulle performance 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, dotandosi di un qualsiasi aggregatore di metriche (Telegraf, Metricbeat, Collectd), in grado di eseguire query SQL personalizzate, di un archivio per queste metriche (InfluxDB, Elasticsearch, Timescaledb) e di uno strumento di visualizzazione (Grafana, Kibana), si pu\u00f2 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 \u00e8 utilizzato il binomio InfluxDB + Grafana insieme a un insieme di query sulle 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 certo che ci sono molte altre applicazioni, fateci sapere nei commenti. E di come (e soprattutto perch\u00e9) automatizzare tutto questo e integrarlo nel proprio pipeline CI\/CD parleremo 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 4.9.10 - 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? \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\" \/>\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) 4.9.10\" \/>\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? \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\" \/>\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 c'\u00e8 di pi\u00f9 semplice? Ognuno di noi pu\u00f2 scrivere una semplice query: digitiamo select, elenchiamo le colonne necessarie, poi from, il nome della tabella, un po' di condizioni in where e voil\u00e0 \u2014 abbiamo i dati utili a portata di mano, (quasi) indipendentemente da quale DBMS ci sia sotto il cofano (o anche se non c'\u00e8 affatto un DBMS). In","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? \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","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"},"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}]}}