{"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\/nl\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"\u00abDatabase as Code\u00bb Ervaring","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u00abDatabase as Code\u00bb Ervaring\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, wat kan er eenvoudiger zijn? Ieder van ons kan een eenvoudige query schrijven - we typen <strong><em>select<\/em><\/strong>, sommen de benodigde kolommen op, dan <strong><em>van<\/em><\/strong>, de naam van de tabel, een beetje voorwaarden in <strong><em>waar<\/em><\/strong> en dat is het - we hebben nuttige gegevens in onze handen, bijna (bijna) ongeacht welke DBMS er onder de motorkap draait (en misschien is het ook <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">geen DBMS \u00fcberhaupt<\/a><\/noindex>). Hierdoor kan de werking met vrijwel elke gegevensbron (relationeel of niet) worden bekeken vanuit het perspectief van gewone code (met alle gevolgen van dien \u2014 versiebeheer, code-review, statische analyse, automatische tests, en zo verder). Dit betreft niet alleen de gegevens zelf, schema's en migraties, maar eigenlijk de hele levenscyclus van de opslag. In dit artikel bespreken we de dagelijkse taken en problemen bij het werken met verschillende databases met de focus op 'database as code'.<\/p>\n<p><\/p>\n<p>We beginnen met <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. De eerste gevechten van het type 'SQL vs ORM' werden al opgemerkt in <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">pre-Peter's Rusland<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Object-relationele mapping<\/h5>\n<p><\/p>\n<p>Voorstanders van ORM waarderen traditioneel de snelheid en eenvoud van ontwikkeling, onafhankelijkheid van DBMS en de netheid van de code. Voor velen van ons ziet de code die met de database werkt (en vaak ook de database zelf)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">ziet er meestal ongeveer zo uit\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>Het model is uitgerust met slimme annotaties, terwijl ergens achter de schermen de dappere ORM tonnen aan SQL-code genereert en uitvoert. Trouwens, ontwikkelaars proberen met alle macht zich te omgeven met kilometers aan abstracties van hun database, wat wijst op een zekere <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">\"SQL haat\"<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Aan de andere kant van de barricade wijzen voorstanders van puur 'handmade'-SQL op de mogelijkheid om het meeste uit hun DBMS te halen zonder extra lagen en abstracties. Dit resulteert in 'data-centric' projecten, waarbij speciaal opgeleide mensen (zij zijn 'database deskundigen', ook wel 'gegevensspecialisten' of 'databasetechnici' genoemd) zich met de database bezighouden, terwijl ontwikkelaars alleen nog maar de kant-en-klare views en opgeslagen procedures hoeven aan te roepen zonder in de details te duiken.<\/p>\n<p><\/p>\n<p>Wat als we het beste van twee werelden combineren? Zoals gedaan in het geweldige hulpmiddel met de levensbevestigende naam <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. Ik zal een paar zinnen delen uit het algemene concept in mijn vrije vertaling, en je kunt er meer over leren. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">hier<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure is een geweldige taal voor het maken van DSL's, maar SQL op zichzelf is al een geweldige DSL, en we hebben er niet nog \u00e9\u00e9n nodig. S-expressies zijn prachtig, maar hier voegen ze niets nieuws toe. Uiteindelijk krijgen we haakjes omwille van haakjes. Het oneens? Wacht dan tot het moment dat de abstractie boven de DB lekt, en je moet worstelen met de functie <em>(raw-sql)<\/em><\/p>\n<p>En wat doen we? Laten we SQL gewoon SQL laten zijn \u2014 \u00e9\u00e9n bestand voor \u00e9\u00e9n aanvraag:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"sql\">-- naam: users-by-country\nselect *\n  from users\n where country_code = :country_code<\/code><\/pre>\n<p><\/p>\n<blockquote><p>\u2026 en lees dat bestand vervolgens, en zet het om in een gewone Clojure-functie:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries \"some\/where\/users_by_country.sql\"\n   {:connection db-spec})\n\n;;; Een functie met de naam `users-by-country` is aangemaakt.\n;;; Laten we deze gebruiken:\n(users-by-country {:country_code \"GB\"})\n;=&gt; ({:name \"Kris\" :country_code \"GB\" ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>Door het principe van \"SQL apart, Clojure apart\" aan te houden, krijgt u:<\/p>\n<ul>\n<li>Geen syntactische verrassingen. Je database (net als elke andere) volgt de SQL-standaard niet voor 100% \u2014 maar dat is voor Yesql niet belangrijk. Je hoeft nooit tijd te verspillen aan het jagen op functies met syntaxis die overeenkomt met SQL. Je hoeft nooit terug te keren naar de functie <em>(raw-sql \"some ('funky' :: SYNTAX)\")<\/em>.<\/li>\n<li>De beste ondersteuning voor de editor. Je editor heeft al geweldige ondersteuning voor SQL. Door SQL als SQL te houden, kun je het eenvoudig gebruiken.<\/li>\n<li>Teamcompatibiliteit. Jouw DBA's kunnen SQL lezen en schrijven die je gebruikt in je Clojure-project.<\/li>\n<li>Eenvoudigere prestatie-instellingen. Moet je een plan opstellen voor een probleemquery? Dat is geen probleem wanneer je query gewoon reguliere SQL is.<\/li>\n<li>Herbruikbaarheid van queries. Sleep dezelfde SQL-bestanden naar andere projecten, omdat het gewoon oude, vertrouwde SQL is \u2014 deel het gewoon.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Volgens mij is het idee heel gaaf en tegelijkertijd heel eenvoudig, waardoor het project talrijke <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">volgers.<\/a><\/noindex> op verschillende talen heeft. En we zullen verder proberen een soortgelijke filosofie toe te passen om SQL-code van de rest ver te scheiden, ver voorbij ORM.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; DB-beheertools<\/h5>\n<p><\/p>\n<p>Laten we beginnen met een eenvoudige alledaagse taak. Vaak moeten we bepaalde objecten in de database zoeken, bijvoorbeeld het vinden van een tabel in een schema en het bestuderen van de structuur (welke kolommen, sleutels, indexen, constraints, enzovoorts worden gebruikt). Van elke grafische IDE of zelfs een bescheiden DB-manager verwachten we in de eerste plaats deze mogelijkheden. Het moet snel gaan en we moeten niet een half uur wachten tot het venster opent met de benodigde informatie (vooral bij een trage verbinding met een externe database), en de informatie moet actueel en vers zijn, niet verouderd en in cache opgeslagen. Hoe complexer en groter de database, en hoe meer databases er zijn, hoe moeilijker het wordt om dit te realiseren.<\/p>\n<p><\/p>\n<p>Maar meestal gooi ik de muis aan de kant en schrijf ik gewoon code. Laten we zeggen dat ik wil ontdekken welke tabellen (en met welke eigenschappen) zich in het schema 'HR' bevinden. In de meeste databasesystemen kan het gewenste resultaat worden bereikt met een eenvoudige query uit 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>De inhoud van dergelijke referentietabellen varieert van database naar database, afhankelijk van de mogelijkheden van elk databasesysteem. In MySQL kun je uit dezelfde referentietabel specifieke parameters voor dit databasesysteem krijgen:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Gebruikte \"engine\" (\"MyISAM\", \"InnoDB\" enz.)\n     , row_format     -- Rijformaat (\"Fixed\", \"Dynamic\" enz.)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle heeft geen information_schema, maar het heeft <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">Oracle-metadata<\/a><\/noindex>, en er ontstaan geen grote problemen:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- Minimum vrije ruimte in een datablok (%)\n     , pct_used       -- Minimum gebruikte ruimte in een datablok (%)\n     , last_analyzed  -- Datum van de laatste statistiekenverzameling\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>ClickHouse vormt hierop geen uitzondering:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select name\n     , engine -- Gebruikte \"engine\" (\"MergeTree\", \"Dictionary\" enz.)\n     , ...\n  from system.tables\n where database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Een soortgelijke actie kan ook in Cassandra worden uitgevoerd (waar er columnfamilies in plaats van tabellen zijn en keyspaces in plaats van schemas):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- De strategie voor het opruimen van gegevens\n     , gc_grace_seconds           -- De levensduur van afval\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Voor de meeste andere databases kunnen ook soortgelijke queries worden bedacht (zelfs in Mongo is er <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">een speciale systeemverzameling<\/a><\/noindex>, die informatie bevat over alle collecties in het systeem).<\/p>\n<p><\/p>\n<p>Het spreekt voor zich dat je op deze manier informatie kunt krijgen, niet alleen over tabellen, maar over elk object. Regelmatig delen vriendelijke mensen dergelijke code voor verschillende databases, zoals in de reeks Habr-artikelen \"Functies voor het documenteren van PostgreSQL-databases\" (<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\">gym<\/a><\/noindex>). Uiteraard is het 'de moeite waard' om al deze queries in je hoofd te houden en ze constant in te voeren, daarom heb ik in mijn favoriete IDE\/editor een vooraf samengestelde set snippets voor vaak gebruikte queries, en hoef ik alleen maar de namen van de objecten in de sjablonen in te voeren.<\/p>\n<p><\/p>\n<p>Uiteindelijk is deze manier van navigeren en het zoeken naar objecten veel flexibeler, bespaart het veel tijd en geeft het precies die informatie in de vorm die op dat moment nodig is (zoals beschreven in de post <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Exporteren van gegevens uit de database in elk formaat: wat IDE's op het IntelliJ-platform kunnen\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Bewerkingen met objecten<\/h5>\n<p><\/p>\n<p>Nadat we de benodigde objecten hebben gevonden en bestudeerd, is het tijd om iets nuttigs met ze te doen. Natuurlijk zonder de vingers van het toetsenbord te halen.<\/p>\n<p><\/p>\n<p>Het is geen geheim dat het eenvoudig verwijderen van een tabel er in bijna alle databases hetzelfde uitziet:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>Het wordt interessanter bij het maken van een tabel. Bijna elke DBMS (inclusief veel NoSQL) kan op de een of andere manier 'create table', en het belangrijkste gedeelte zal weinig verschillen (naam, lijst met kolommen, datatypes), maar de andere details kunnen sterk vari\u00ebren en hangen af van de interne structuur en mogelijkheden van de specifieke DBMS. Mijn favoriete voorbeeld \u2014 in de documentatie van Oracle zijn er alleen al 'blote' BNF's voor de syntaxis van 'create table'. <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">31 pagina's in beslag.<\/a><\/noindex>. Andere databases hebben meer bescheiden mogelijkheden, maar elke database heeft ook veel interessante en unieke functies voor het cre\u00ebren van tabellen (<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>). Het is twijfelachtig of een grafische 'wizard' van de zoveelste IDE (vooral een universele) alle deze mogelijkheden volledig kan dekken, en als dat kan, is het een schouwspel dat niet voor de zwakkeren van hart is. Tegelijkertijd is een correct en tijdig geschreven statement belangrijk. <strong><em>create table<\/em><\/strong> je in staat om zonder moeite van al deze functies gebruik te maken, en om de opslag en toegang tot je gegevens betrouwbaar, optimaal en zo aangenaam mogelijk te maken.<\/p>\n<p><\/p>\n<p>In veel DBMS zijn er ook specifieke objecttypen die in andere DBMS ontbreken. Bovendien kunnen we niet alleen bewerkingen uitvoeren op databaseobjecten, maar ook op de DBMS zelf, zoals een proces 'killen', een bepaald geheugenbereik vrijmaken, tracing inschakelen, in de 'read only' modus gaan en nog veel meer.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">Laten we nu even wat tekenen.<\/h5>\n<p><\/p>\n<p>Een van de meest voorkomende taken is het opstellen van een diagram met databaseobjecten, waarin je op een mooie afbeelding de objecten en de verbindingen daartussen kunt zien. Praktisch elke grafische IDE, afzonderlijke 'command line'-hulpmiddelen, gespecialiseerde grafische tools en modelleringsprogramma's kunnen dat. Ze tekenen iets 'zoals ze kunnen', en je kunt dit proces een beetje be\u00efnvloeden met behulp van enkele parameters in het configuratiebestand of selectievakjes in de interface.<\/p>\n<p><\/p>\n<p>Maar deze kwestie kan veel eenvoudiger, flexibeler en eleganter worden opgelost, natuurlijk met code. Voor het maken van diagrammen van elke complexiteit hebben we meteen verschillende gespecialiseerde opmaaktalen (DOT, GraphML, enz.), en daarnaast een hele reeks applicaties (GraphViz, PlantUML, Mermaid) die deze instructies kunnen lezen en visualiseren in de meest diverse formaten. En we weten al hoe we informatie over de objecten en de verbanden daartussen kunnen verkrijgen.<\/p>\n<p><\/p>\n<p>Laten we een klein voorbeeld geven van hoe dit eruit zou kunnen zien, met gebruik van PlantUML en <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">een demonstratiedatabase voor PostgreSQL.<\/a><\/noindex> (links de SQL-query die de benodigde instructie voor PlantUML genereert, en rechts het resultaat):<\/p>\n<p>\n<img decoding=\"async\" alt=\"\u00abDatabase as Code\u00bb Ervaring\" 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>En als je een beetje moeite doet, kun je op basis van <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">de ER-sjabloon voor PlantUML<\/a><\/noindex> iets heel nauwkeurigs krijgen dat lijkt op een echte ER-diagram:<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">Een SQL-query die een beetje ingewikkelder is.<\/b><\/p>\n<pre><code class=\"sql\">-- Koptekst\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        verberg methoden\n        verberg stereotypen&#039;\n union all\n-- Tabellen\nselect format(&#039;Table(%s, &quot;%s n informatie over %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-- Relaties tussen tabellen\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;Een %s kan veel %s hebben&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-- Voettekst\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"\u00abDatabase as Code\u00bb Ervaring\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Als je goed kijkt, dan gebruiken veel visualisatie-instrumenten onderhuids ook vergelijkbare queries. Het zijn echter vaak queries die diep \"verankerd\" zijn in de code van de applicatie en moeilijk te begrijpen zijn. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">'verankerd' in de code van de applicatie zelf en moeilijk te begrijpen.<\/a><\/noindex>Statistieken en monitoring.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">Meten en bewaking.<\/h5>\n<p><\/p>\n<p>Laten we het hebben over een traditioneel uitdagend onderwerp: databaseprestaties monitoren. Ik herinner me een kleine waargebeurde verhaal dat een \"vriend van mij\" vertelde. In een recent project leefde er eens een krachtige DBA, en weinig ontwikkelaars kende hem persoonlijk, laat staan dat ze hem ooit in het echt hadden gezien (hoewel hij, volgens de geruchten, ergens in een aangrenzend gebouw werkte). Op het moment van \"X\", wanneer het productiesysteem van een grote retailer weer eens \"niet goed voelde\", stuurde hij in stilte screenshots van grafieken uit de Oracle Enterprise Manager, waarop hij belangrijke punten met een rode marker markeerde voor \"duidelijkheid\" (wat zachtjes gezegd weinig hielp). En zo moest men op basis van deze \"foto\" problemen oplossen. Daarbij had niemand toegang tot de kostbare (in beide betekenissen van het woord) Enterprise Manager, omdat het systeem complex en duur was, en men vreesde dat de ontwikkelaars per ongeluk iets zouden breken. Daarom vonden de ontwikkelaars op \"empirische\" wijze de plaats en oorzaak van de vertragingen en gaven een patch uit. Als er geen dreigend schrijven van de DBA in de nabije toekomst terugkwam, haalden ze opgelucht adem en keerden ze terug naar hun huidige taken (tot de volgende Brief).<\/p>\n<p><\/p>\n<p>Maar het monitoringsproces kan er veel leuker en vriendelijker uitzien, en het belangrijkste is dat het toegankelijk en transparant is voor iedereen. Ten minste het basisgedeelte, als aanvulling op de hoofmonitoringsystemen (die ongetwijfeld nuttig zijn en in veel gevallen onmisbaar). Elke DBMS is bereid om informatie over zijn huidige toestand en prestaties vrijelijk en volledig kosteloos te delen. In hetzelfde \"bloederige\" Oracle DB kan vrijwel elke informatie over prestaties worden verkregen uit de systeemweergaven, van processen en sessies tot de status van de buffer cache (bijvoorbeeld, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">DBA-scripts<\/a><\/noindex>, sectie \"Monitoring\"). In Postgresql zijn er ook tal van systeemweergaven beschikbaar voor <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">database monitoring<\/a><\/noindex>, met name van onschatbare waarde in het dagelijks leven van elke DBA, zoals <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 is er zelfs een aparte schema bedoeld voor <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. En in Mongo is er een ingebouwde <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profiler<\/a><\/noindex> die prestatiegegevens in een systeemcollectie aggregeert <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>Dus, gewapend met een of andere metric aggregator (Telegraf, Metricbeat, Collectd), die aangepaste sql-queries kan uitvoeren, een opslag voor deze metrics (InfluxDB, Elasticsearch, Timescaledb) en een visualisatietool (Grafana, Kibana), kan men een vrij eenvoudige en flexibele monitoring systeem opzetten dat nauw ge\u00efntegreerd is met andere algemene systeem metrics (verkregen bijvoorbeeld van de applicatieserver, van het besturingssysteem, enz.). Zoals dat is gedaan in pgwatch2, waar de combinatie InfluxDB + Grafana en een set queries naar systeemschema's wordt gebruikt, waar ook aangepaste queries aan toegevoegd kunnen worden. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">toevoegen.<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Total<\/h2>\n<p><\/p>\n<p>En dit is slechts een voorlopige lijst van wat je met onze database kunt doen via gewone SQL-code. Ik ben er zeker van dat er nog veel meer toepassingen zijn, laat het ons alsjeblieft weten in de reacties. En over hoe (en vooral waarom) we dit allemaal kunnen automatiseren en opnemen in onze CI\/CD-pipeline, daar praten we de volgende keer over.<\/p>\n<p>Bron: <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.3 - 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\/nl\/blog\/administrirovanie\/database-as-sode-experience\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\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\/nl\/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 als Code\u00bb Ervaring | ProHoster","description":"SQL, wat kan er eenvoudiger zijn?","canonical_url":"https:\/\/prohoster.info\/nl\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}