{"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\/et\/blog\/administrirovanie\/database-as-sode-experience","title":{"rendered":"\u201eAndmebaas kui kood\u201c kogemus","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"\u201eAndmebaas kui kood\u201c kogemus\" src=\"\/wp-content\/uploads\/2020\/06\/a1ac23deeded97559fbe787ed09184a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>SQL, mis v\u00f5iks olla lihtsam? Iga\u00fchel meist on v\u00f5imalik kirjutada lihtne p\u00e4ring \u2014 kirjutame <strong><em>select<\/em><\/strong>, loetleme vajalikud veerud, siis <strong><em>from<\/em><\/strong>, tabeli nime, paar tingimust <strong><em>where<\/em><\/strong> ja k\u00f5ik \u2014 kasulikud andmed on meil taskus, peaaegu s\u00f5ltumata sellest, milline andmebaas praegu t\u00f6\u00f6tamas on (v\u00f5i ei ole see <noindex><a rel=\"nofollow\" href=\"https:\/\/osquery.io\/\">\u00fcldse andmebaas<\/a><\/noindex>). Tulemuseks saab mistahes andmeallika (suhteline v\u00f5i mitte) t\u00f6\u00f6d vaadelda kui tavalist koodi (k\u00f5ikide sellele j\u00e4rgneva \u2014 versioonihalduse, koodikontrolli, staatilise anal\u00fc\u00fcsi, automaatkatsetuste ja muu sarnasega). Ja see puudutab mitte ainult andmeid, skeeme ja migreerimist, vaid kogu talletamise elu. Selles artiklis r\u00e4\u00e4gime igap\u00e4evastest \u00fclesannetest ja probleemidest, mis on seotud erinevate andmebaasidega, silmas pidades<\/p>\n<p><\/p>\n<p>Ja alustame otse <noindex><a rel=\"nofollow\" href=\"https:\/\/www.yegor256.com\/2014\/12\/01\/orm-offensive-anti-pattern.html\">ORM<\/a><\/noindex>. Esimesed lahingud stiilis <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/904343\/orm-vs-sql\">enne Peeter I<\/a><\/noindex>.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h5 id=\"obektno-relyacionnyy-maping\">Objekti-relatsiooniline kaardistamine<\/h5>\n<p><\/p>\n<p>ORM-i pooldajad hindavad traditsiooniliselt arenduse kiirust ja lihtsust, s\u00f5ltumatust andmebaasidest ning koodi puhtust. Paljude jaoks meie seas n\u00e4eb andmebaasiga t\u00f6\u00f6tamise kood (ja sageli ka sama andmebaas)<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">n\u00e4eb tavaliselt v\u00e4lja umbes nii\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>Mudel on kaunistatud nutikate annotatsioonidega, ja kusagil lava taga genereerib ja k\u00e4ivitab vapper ORM tonnide viisi mingit SQL-koodi. \u00dctlemata selgelt, arendajad p\u00fc\u00fcavad igal juhul t\u00f5kestada ennast oma andmebaasi eest kilomeetrite kaupa abstraktsioone, mis viitab teatud <noindex><a rel=\"nofollow\" href=\"https:\/\/www.sql.ru\/forum\/1303231\/prichiny-nenavisti-k-yazyku-sql\">\"SQL-i vihkamine\"<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Teisest k\u00fcljest m\u00e4rkavad puhta \"handmade\"-SQL-i toetajad v\u00f5imalust oma andmebaasist maksimaalselt v\u00e4lja pigistada ilma lisakihtide ja abstraheeringuteta. Tulemuseks on \u201eandmep\u00f5hised\u201c projektid, kus andmete \u00fcle tegelevad spetsiaalselt koolitatud inimesed (nemad on \"andmebaasi spetsialistid\", \"andmebaasi arendajad\", \"andmebaasi t\u00f6\u00f6hobused\" jne), ja arendajatele j\u00e4\u00e4b vaid valmistehtud vaadete ja salvestatud protseduuride \u201ev\u00e4ljat\u00f5mbamine\u201c, ilmaj\u00e4tmine detailidesse s\u00fc\u00fcvimisest.<\/p>\n<p><\/p>\n<p>Aga mis kui v\u00f5tta parem osa kahest maailmast? Kuidas seda on tehtud imelises t\u00f6\u00f6riistas, millel on eluj\u00f5uline nimi <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql\">Yesql<\/a><\/noindex>. T\u00f5in v\u00e4lja paar rida \u00fcldkonseptsioonist minu vabalt t\u00f5lgitud versioonis, kuid selle kohtadega saab tutvuda p\u00f5hjalikumalt <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#rationale\">siin<\/a><\/noindex>.<\/p>\n<p><\/p>\n<blockquote><p>Clojure on suurep\u00e4rane keel DSL-ide loomiseks, kuid SQL iseenesest on juba hea DSL, ja me ei vaja veel \u00fchte. S-i avaldised on imelised, kuid siin ei lisata need midagi uut. Tulemuseks on sulud ainult sulude p\u00e4rast. Kui ei n\u00f5ustu? Siis oodake hetke, kui abstraheerimine andmebaasi \u00fcle muutub lekivaks, ja te alustate t\u00fcli funktsiooni... <em>(raw-sql)<\/em><\/p>\n<p>Ja mida teha? J\u00e4tame SQL lihtsalt tavaliseks SQL-iks \u2014 \u00fcks fail \u00fche p\u00e4ringu jaoks:<\/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 ja seej\u00e4rel loe see fail ning muuda see tavaliseks Clojure funktsiooniks:<\/p><\/blockquote>\n<p><\/p>\n<pre><code class=\"lisp\">(defqueries \"some\/where\/users_by_country.sql\"\n   {:connection db-spec})\n\n;;; Funksiooni nimega `users-by-country` on loodud.\n;;; Kasutame seda:\n(users-by-country {:country_code \"GB\"})\n;=&gt; ({:name \"Kris\" :country_code \"GB\" ...} ...)<\/code><\/pre>\n<p><\/p>\n<blockquote><p>J\u00e4rgides printsiipi \"SQL eraldi, Clojure eraldi\", saate:<\/p>\n<ul>\n<li>Mitte mingeid s\u00fcntaktilisi \u00fcllatusi. Teie andmebaas (nagu iga teine) ei vasta 100% SQL standardile \u2014 kuid Yesqli jaoks ei ole see oluline. Te ei pea kunagi aega kulutama funktsioonide jahtimisele, mille s\u00fcntaks vastab SQL-ile. Te ei pea kunagi tagasi p\u00f6\u00f6rduma funktsiooni <em>(raw-sql \"some (\u2018funky\u2019 :: SYNTAX)\")<\/em>.<\/li>\n<li>Parim toimetaja tugi. Teie toimetaja juba toetab SQLi suurep\u00e4raselt. SQL-i s\u00e4ilitades saate seda lihtsalt kasutada.<\/li>\n<li>Meeskonna \u00fchilduvus. Teie DBA-d saavad lugeda ja kirjutada SQL-i, mida te kasutate oma Clojure projektis.<\/li>\n<li>Lihtsustatud j\u00f5udluse seadistamine. Peate koostama plaani probleemse p\u00e4ringu jaoks? See pole probleem, kui teie p\u00e4ring on tavaline SQL.<\/li>\n<li>P\u00e4ringute taaskasutamine. T\u00f5stke need samad SQL-failid teistesse projektidesse, sest see on lihtsalt hea vana SQL \u2014 jagage seda lihtsalt.<\/li>\n<\/ul>\n<p>\n<\/p><\/blockquote>\n<p>Minu arvates on idee v\u00e4ga lahe ja samas v\u00e4ga lihtne, t\u00e4nu millele on projekt omandanud palju <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/krisajenkins\/yesql#other-languages\">j\u00e4rgijaid<\/a><\/noindex> erinevates keeltes. Ja proovime edasi rakendada sarnast filosoofiat SQL-koodi eraldamiseks k\u00f5igest muust, kaugel ORM-ist.<\/p>\n<p><\/p>\n<h5 id=\"ide--db-menedzhery\">IDE &amp; DB-haldurid<\/h5>\n<p><\/p>\n<p>Alustame lihtsa igap\u00e4evase \u00fclesandega. Sageli peame otsima andmebaasist mingisuguseid objekte, n\u00e4iteks leidma skeemist tabeli ja uurima selle struktuuri (millised veerud, v\u00f5tmed, indeksid, piirangud jne on kasutusel). Igal graafilisel IDE-l v\u00f5i igasugusel DB-manager\u2019il ootame esmaj\u00e4rjekorras just neid v\u00f5imalusi. Et see k\u00e4iks kiiresti ja ei peaks ootama pool tundi, kuni vajalikku infot kuvab aken (eriti aeglaste kaugandmebaaside\u00fchenduste puhul), ning et saadud teave oleks v\u00e4rske ja aktuaalne, mitte t\u00f5mmatud vana vahem\u00e4lust. Mida keerukam ja suurem on andmebaas ja mida rohkem on neid, seda keerulisem on see teha.<\/p>\n<p><\/p>\n<p>Kuid tavaliselt viskan hiire k\u00f5rvale ja kirjutan lihtsalt koodi. Oletame, et tuleb v\u00e4lja selgitada, milliseid tabeleid (ja milliste omadustega) sisaldab skeem \"HR\". Enamikus andmebaasi halduss\u00fcsteemides saab vajalikku tulemust kergesti k\u00e4tte j\u00e4rgmise lihtsa p\u00e4ringu abil information_schema-st:<\/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>Andmebaasist andmebaasi sisaldus varieerub s\u00f5ltuvalt iga andmebaasihalduss\u00fcsteemi v\u00f5imalustest. N\u00e4iteks MySQL-i puhul v\u00f5ib sellelt samalt registrilt saada selle andmebaasihalduss\u00fcsteemi spetsiifilisi tabeli parameetreid:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , storage_engine -- Kasutatav \"mootor\" (\"MyISAM\", \"InnoDB\" jne)\n     , row_format     -- Rea vormaat (\"Fixed\", \"Dynamic\" jne)\n     , ...\n  from information_schema.tables\n where schema = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Oracle ei tunne information_schema-d, aga sellel on olemas <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Oracle_metadata\">Oracle metadata<\/a><\/noindex>, ja suuri probleeme ei teki:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select table_name\n     , pct_free       -- Minimaalne vaba ruum andmepaketis (%)\n     , pct_used       -- Minimaalne kasutatud ruum andmepaketis (%)\n     , last_analyzed  -- Viimane statistika kogumise kuup\u00e4ev\n     , ...\n  from all_tables\n where owner = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Sama k\u00e4ib ka ClickHouse'i kohta:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select name\n     , engine -- Kasutatav \"mootor\" (\"MergeTree\", \"Dictionary\" jne)\n     , ...\n  from system.tables\n where database = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Midagi sarnast saab teha ka Cassaandmikus (kus on columnfamilies tabelite asemel ja keyspace\u2019id skeemide asemel):<\/p>\n<p><\/p>\n<pre><code class=\"sql\">select columnfamily_name\n     , compaction_strategy_class  -- Pr\u00fcgi kogumise strateegia\n     , gc_grace_seconds           -- Pr\u00fcgi eluiga\n     , ...\n  from system.schema_columnfamilies\n where keyspace_name = 'HR'<\/code><\/pre>\n<p><\/p>\n<p>Enamikule teistest andmebaasidest v\u00f5ib ka sarnaseid p\u00e4ringuid v\u00e4lja m\u00f5elda (isegi Mongos on <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/reference\/system-collections\/#%3Cdatabase%3E.system.namespaces\">eriline s\u00fcsteemikollektsioon<\/a><\/noindex>, mis sisaldab teavet k\u00f5igi s\u00fcsteemi kollektsioonide kohta).<\/p>\n<p><\/p>\n<p>Muidugi, sellisel viisil saab teavet saada mitte ainult tabelite, vaid ka igasuguste objektide kohta. Aeg-ajalt jagavad head inimesed sellist koodi erinevate andmebaaside jaoks, n\u00e4iteks Habr artiklite sarjas \"Andmebaaside PostgreSQL dokumenteerimise funktsioonid\" (<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>). Muidugi, hoida kogu see hulk p\u00e4ringuid peas ja pidevalt neid kirjutada pole just \"nauditav\" tegevus, seet\u00f5ttu on minu lemmik IDE\/editoris juba ettevalmistatud komplekt snippette sageli kasutatavatele p\u00e4ringutele, ja j\u00e4\u00e4b ainult sisestada objektide nimed \u0161ablooni.<\/p>\n<p><\/p>\n<p>Nii et selline navigeerimise ja objektide otsimise meetod on palju paindlikum, s\u00e4\u00e4stab palju aega ning v\u00f5imaldab saada t\u00e4pselt seda teavet ja sellisel kujul, nagu praegu vajalik on (nagu n\u00e4iteks postituses <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/company\/JetBrains\/blog\/342094\">\"Andmete eksportimine andmebaasist igas formaadis: mida suudavad IDE-d IntelliJ platvormil\"<\/a><\/noindex>).<\/p>\n<p><\/p>\n<h5 id=\"operacii-s-obektami\">Objektidega operatsioonid<\/h5>\n<p><\/p>\n<p>P\u00e4rast seda, kui oleme leidnud ja uurinud vajalikud objektid, on \u00f5ige aeg nendega midagi kasulikku teha. Loomulikult, hoides samal ajal s\u00f5rmed klaviatuurilt eemal.<\/p>\n<p><\/p>\n<p>Ei ole saladus, et lihtne tabeli kustutamine n\u00e4eb v\u00e4lja peaaegu sama k\u00f5igis andmebaasides:<\/p>\n<p><\/p>\n<pre><code class=\"sql\">drop table hr.persons<\/code><\/pre>\n<p><\/p>\n<p>Kuid tabeli loomine on juba huvitavam. Praktiselt igas andmebaasis (sealhulgas paljudes NoSQL-s\u00fcsteemides) on mingil kujul olemas \"create table\" k\u00e4sk, ja selle peamine osa erineb v\u00e4he (nimi, veergude nimekiri, andmet\u00fc\u00fcbid), kuid \u00fclej\u00e4\u00e4nud detailid v\u00f5ivad oluliselt erineda ning s\u00f5ltuvad konkreetse andmebaasi sisemisest struktuurist ja v\u00f5imalustest. Minu lemmikn\u00e4ide - Oracle'i dokumentatsioonis on ainult \u00fched \"paljad\" BNF-d \"create table\" s\u00fcntaksile. <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.oracle.com\/en\/database\/oracle\/oracle-database\/19\/sqlrf\/sql-language-reference.pdf\">t\u00e4idab 31 lehek\u00fclge<\/a><\/noindex>. Teised andmebaasid pakuvad tagasihoidlikumaid v\u00f5imalusi, kuid iga\u00fchel on ka palju huvitavaid ja ainulaadseid funktsioone tabelite loomisel (<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>). T\u00f5en\u00e4oliselt ei suuda \u00fckski graafiline \"wizard\" j\u00e4rgmistest IDE-dest (eriti universaalsetest) t\u00e4ielikult katta k\u00f5iki neid omadusi, ja kui suudabki, on see vaatepilt mitte n\u00f5rgema s\u00fcdamega inimestele. Samas \u00f5igesti ja \u00f5igeaegselt kirjutatud k\u00e4sk. <strong><em>create table<\/em><\/strong> kasutada k\u00f5iki neid v\u00f5imalusi t\u00f5rgeteta, tagades teie andmete salvestamise ja juurdep\u00e4\u00e4su usaldusv\u00e4\u00e4rsuse, optimaalsuse ja maksimaalse mugavuse.<\/p>\n<p><\/p>\n<p>Samuti on paljudes andmebaasides oma spetsiifilised objektit\u00fc\u00fcbid, mida teistes andmebaasides ei leidu. Lisaks saame teostada operatsioone mitte ainult andmebaasi objektide, vaid ka andmebaasi enda \u00fcle, n\u00e4iteks \"tappa\" protsessi, vabastada mingit m\u00e4lu, aktiveerida j\u00e4lgimise, minna \"read only\" re\u017eiimi ja palju muud.<\/p>\n<p><\/p>\n<h5 id=\"a-teper-nemnogo-porisuem\">N\u00fc\u00fcd joonistame natuke.<\/h5>\n<p><\/p>\n<p>\u00dcks levinumaid \u00fclesandeid on luua diagramm andmebaasi objektidest, et ilusas pildis n\u00e4ha objekte ja nende vahelisi seoseid. Peaaegu iga graafiline IDE, eraldi \u201ecommand line\u201c utiliidid, spetsialiseeritud graafilised t\u00f6\u00f6riistad ja mudelid suudavad seda teha. Nad joonistavad teile midagi \"nagu oskavad\", ja selle protsessi m\u00f5jutamiseks saate kasutada ainult m\u00f5ningaid parameetreid konfiguratsioonifailis v\u00f5i ruutu kasutajaliideses.<\/p>\n<p><\/p>\n<p>Kuid seda probleemi saab lahendada palju lihtsamalt, paindlikumalt ja elegantsemalt, loomulikult koodi abil. Igasuguste diagrammide koostamiseks on meil mitmeid spetsialiseeritud markeerimiskeeli (DOT, GraphML jne), ja nende jaoks terve rida rakendusi (GraphViz, PlantUML, Mermaid), mis oskavad selliseid juhiseid lugeda ja visualiseerida erinevates formaatides. \u00dcldiselt teame, kuidas hankida teavet objektide ja nende seoste kohta.<\/p>\n<p><\/p>\n<p>Tuletame meelde v\u00e4ikese n\u00e4ite selle kohta, kuidas see v\u00f5iks v\u00e4lja n\u00e4ha, kasutades PlantUML ja <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/postgrespro\/blog\/316428\/\">demo andmebaasi PostgreSQL jaoks.<\/a><\/noindex> (vasakul SQL-p\u00e4ring, mis genereerib vajaliku juhise PlantUML jaoks, ja paremal tulemus):<\/p>\n<p>\n<img decoding=\"async\" alt=\"\u201eAndmebaas kui kood\u201c kogemus\" 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>Ja kui natuke vaeva n\u00e4ha, siis ER-mallile toetudes <noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/QuantumGhost\/0955a45383a0b6c0bc24f9654b3cb561\">PlantUML jaoks<\/a><\/noindex> saame midagi, mis sarnaneb t\u00f5elise ER-diagrammiga:<\/p>\n<p><\/p>\n<p>                        <b class=\"spoiler_title\">SQL-p\u00e4ring on veidi keerulisem.<\/b><\/p>\n<pre><code class=\"sql\">-- Pealkiri\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-- Tabelid\nselect format(&#039;Table(%s, &quot;%s n information about %s&quot;) {&#039;||chr(10), table_name, table_name, table_name) ||\n       (select string_agg(column_name || &#039; &#039; || upper(udt_name), chr(10))\n          from information_schema.columns\n         where table_schema = &#039;public&#039;\n           and table_name = t.table_name) || chr(10) || &#039;}&#039;\n  from information_schema.tables t\n where table_schema = &#039;public&#039;\n union all\n-- Suhted tabelite vahel\nselect distinct ccu.table_name || &#039; &quot;1&quot; --&amp;gt; &quot;0..N&quot; &#039; || tc.table_name || format(&#039; : &quot;A %s may haven many %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-- Jalus\nselect &#039;@enduml&#039;<\/code><\/pre>\n<p>\n<img decoding=\"async\" alt=\"\u201eAndmebaas kui kood\u201c kogemus\" src=\"\/wp-content\/uploads\/2020\/06\/bd45420a4fd1bdfcf20cbe74a0638c7b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p>Kui t\u00e4helepanelikult vaadata, siis paljud visualiseerimist\u00f6\u00f6riistad kasutavad ka alla sarnaseid p\u00e4ringuid. T\u00f5si, et need p\u00e4ringud on tavaliselt s\u00fcgavalt <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgmodeler\/pgmodeler\/blob\/9c615c0b0871df3cd649983ce61e802b0ff0137b\/schemas\/catalog\/table.sch\">\"koodis\" on need rakenduse enda koodis ning keerulised m\u00f5ista.<\/a><\/noindex>, r\u00e4\u00e4kimata nende modifitseerimisest.<\/p>\n<p><\/p>\n<h5 id=\"metriki-i-monitoring\">M\u00f5\u00f5dikud ja j\u00e4lgimine.<\/h5>\n<p><\/p>\n<p>Liigume edasi traditsiooniliselt keerulisse teema \u2014 andmebaasi j\u00f5udluse j\u00e4lgimine. M\u00e4letan \u00fchte v\u00e4ikesed t\u00f5estis\u00fcndinud lugu, mille r\u00e4\u00e4kis mulle \"\u00fcks minu s\u00f5ber\". \u00dchel projektil elas ja toimetas \u00fcks v\u00f5imas DBA, kellel oli vaid v\u00e4hestel arendajatel isiklik tuntus ja kes polnud paljudele kunagi silma j\u00e4\u00e4nud (kuigi kuulujutud v\u00e4itsid, et ta t\u00f6\u00f6tas kusagil naabruses). Kui \"X-tunnil\", mil suure jaeharja tootmiss\u00fcsteem hakkas j\u00e4lle \"halvasti tundma\", saatis ta vaikselt ekraanipilte orakli Enterprise Managerist, kus ta hoolikalt r\u00f5hutas kriitilisi kohti punase markeriga \"m\u00f5istmise huvides\" (see aitas, pehmelt \u00f6eldes, v\u00e4he). Nii tuli neid \"fotograafiaid\" ravida. Samal ajal ei olnud kellelgi juurdep\u00e4\u00e4su sellele kallile (kaudses t\u00e4henduses) Enterprise Managerile, kuna s\u00fcsteem oli keeruline ja kallis; \u00e4kki \"arendajad juhuslikult midagi katki teevad\". Seet\u00f5ttu leidisid arendajad \"empiirilisel\" teel probleemi ja aeglustumise p\u00f5hjused ning v\u00e4ljastasid plaastri. Kui hulga DBA \u00e4hvardavat kirja ei tulnud varsti uuesti, siis k\u00f5ik hingasid kergendatult v\u00e4lja ja p\u00f6\u00f6rdusid tagasi oma praeguste \u00fclesannete juurde (kuni uue kirja saabumiseni).<\/p>\n<p><\/p>\n<p>Aga j\u00e4lgimisprotsess v\u00f5ib olla palju l\u00f5busam ja s\u00f5bralikuma n\u00e4oga ning mis k\u00f5ige t\u00e4htsam \u2014 kergesti ligip\u00e4\u00e4setav ja l\u00e4bipaistev k\u00f5igile. Igasugune andmebaas on valmis jagama oma praegust seisundit ja j\u00f5udlust vabalt ja tasuta. Samas \"vereseguses\" Oracle DB-s suudab pea iga j\u00f5udlusinfo hankida s\u00fcsteemi vaadetest, alates protsessidest ja sessioonidest kuni puhverm\u00e4lukeskkonna olekuni (n\u00e4iteks, <noindex><a rel=\"nofollow\" href=\"https:\/\/oracle-base.com\/dba\/scripts\">DBA skriptid<\/a><\/noindex>, jaotis \"Monitoring\" ). Postgresql-is on samuti terve rida s\u00fcsteemi vaateid, et <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/static\/monitoring-stats.html\">andmebaasi t\u00f6\u00f6 j\u00e4lgimine<\/a><\/noindex>, sealhulgas m\u00f5ned, mis on asendamatud iga DBA igap\u00e4evaelus, nagu <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>. MySQL-is on selle jaoks isegi eraldi skeem <noindex><a rel=\"nofollow\" href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/performance-schema-table-descriptions.html\">performance_schema<\/a><\/noindex>. Ja MongoDB-s on sisseehitatud <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.mongodb.com\/manual\/tutorial\/manage-the-database-profiler\/\">profilera<\/a><\/noindex> , mis kogub j\u00f5udlusandmeid s\u00fcsteemilikku kollektsiooni <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>Seega, varustades end m\u00f5ne m\u00f5\u00f5dikute koguja (Telegraf, Metricbeat, Collectd) ja m\u00f5\u00f5dikute salvestiga (InfluxDB, Elasticsearch, Timescaledb) ning visualiseerijaga (Grafana, Kibana), on v\u00f5imalik luua piisavalt kerge ja paindlik j\u00e4lgimiss\u00fcsteem, mis on tihedalt integreeritud teiste \u00fcldiste s\u00fcsteemimeetriatega (mida saadakse n\u00e4iteks rakenduste serverilt, operatsioonis\u00fcsteemilt jne). Nagu n\u00e4iteks on tehtud pgwatch2-s, kus kasutatakse kombinatsiooni InfluxDB + Grafana ja komplekti p\u00e4ringutest s\u00fcsteemivaadetele, kuhu saab ka lisada kohandatud p\u00e4ringuid. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/cybertec-postgresql\/pgwatch2#adding-metrics\">lisada kohandatud p\u00e4ringud<\/a><\/noindex>.<\/p>\n<p><\/p>\n<h2 id=\"itogo\">Kokkuv\u00f5ttes<\/h2>\n<p><\/p>\n<p>Ja see on ainult umbkaudne nimekiri sellest, mida meie andmebaasiga saab teha tavalise SQL-koodi abil. Olen kindel, et leidub veel palju kasutusv\u00f5imalusi, kirjutage kommentaaridesse. Ja sellest, kuidas (ja mis k\u00f5ige t\u00e4htsam, miks) k\u00f5ik see automatiseerida ja oma CI\/CD torujuhtmesse kaasata, r\u00e4\u00e4gime j\u00e4rgmine kord.<\/p>\n<p>Allikas: <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\/et\/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=\"et_EE\" \/>\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\/et\/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 kogemus | ProHoster","description":"SQL, mis v\u00f5iks olla lihtsam?","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/database-as-sode-experience","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","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\/et\/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\/et\/wp-json\/wp\/v2\/posts\/83649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=83649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/83649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/83650"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=83649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=83649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=83649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}