"Database as Code" nga Kasinatian

"Database as Code" nga Kasinatian

SQL, unsa ang mahimong mas simple? Ang matag usa kanato makasulat ug usa ka yano nga hangyo - kita mag-type pagpili, ilista ang gikinahanglan nga mga kolum, unya gikan sa, ngalan sa lamesa, pipila ka mga kondisyon sa diin ug kana ra - ang mapuslanon nga datos naa sa among bulsa, ug (halos) bisan unsa pa ang DBMS nga naa sa ilawom sa tabon nianang panahona (o tingali dili usa ka DBMS). Ingon usa ka sangputanan, ang pagtrabaho sa hapit bisan unsang gigikanan sa datos (relasyonal ug dili sa ingon) mahimong isipon gikan sa punto sa pagtan-aw sa ordinaryo nga code (uban ang tanan nga gipasabut niini - pagkontrol sa bersyon, pagrepaso sa code, static nga pagtuki, autotest, ug kana ang tanan). Ug kini magamit dili lamang sa mga datos mismo, mga laraw ug mga paglalin, apan sa kinatibuk-an sa tibuuk nga kinabuhi sa pagtipig. Niini nga artikulo maghisgot kita mahitungod sa adlaw-adlaw nga mga buluhaton ug mga problema sa pagtrabaho sa nagkalain-laing mga database ubos sa lente sa "database isip code".

Ug magsugod kita gikan mismo ORM. Ang unang mga gubat sa "SQL vs ORM" nga matang namatikdan balik pre-Petrine Rus'.

Pagmapa nga may kalabotan sa butang

Ang mga tigsuporta sa ORM tradisyonal nga nagpabili sa katulin ug kasayon ​​sa pag-uswag, kagawasan gikan sa DBMS ug limpyo nga code. Alang sa kadaghanan kanato, ang code alang sa pagtrabaho kauban ang database (ug kasagaran ang database mismo)

kasagaran murag ingon ani...

@Entity
@Table(name = "stock", catalog = "maindb", uniqueConstraints = {
        @UniqueConstraint(columnNames = "STOCK_NAME"),
        @UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "STOCK_ID", unique = true, nullable = false)
    public Integer getStockId() {
        return this.stockId;
    }
  ...

Ang modelo gibitay uban sa maalamon nga mga anotasyon, ug sa luyo sa mga talan-awon ang usa ka maisog nga ORM nagmugna ug nagpatuman sa tonelada sa pipila ka SQL code. Pinaagi sa dalan, ang mga nag-develop naningkamot sa ilang labing maayo nga ihimulag ang ilang kaugalingon gikan sa ilang database nga adunay mga kilometro nga abstraction, nga nagpakita sa pipila "SQL pagdumot".

Sa pikas bahin sa mga barikada, ang mga sumusunod sa lunsay nga "kamot" nga SQL namatikdan ang abilidad sa pagpuga sa tanan nga juice gikan sa ilang DBMS nga wala’y dugang nga mga layer ug abstraction. Ingon nga resulta, ang mga "data-centric" nga mga proyekto nagpakita, diin ang mga espesyal nga gibansay nga mga tawo nalambigit sa database (sila usab mga "basicist", sila usab "basicists", sila usab "basdeners", ug uban pa), ug ang mga developers kinahanglan lamang nga "ibira" ang mga naandam nga pagtan-aw ug gitipigan nga mga pamaagi, nga wala moadto sa mga detalye.

Unsa kaha kon kita adunay labing maayo sa duha ka kalibutan? Giunsa kini gihimo sa usa ka talagsaon nga himan nga adunay usa ka ngalan nga nagpamatuod sa kinabuhi Yesql. Maghatag ako usa ka magtiayon nga linya gikan sa kinatibuk-ang konsepto sa akong libre nga paghubad, ug mahimo nimong pamilyar kini sa mas detalyado. dinhi.

Ang Clojure usa ka cool nga lengguwahe alang sa paghimo og mga DSL, apan ang SQL mismo usa ka cool nga DSL, ug wala na kami magkinahanglan ug lain. Nindot ang mga S-expression, pero wala silay gidugang nga bag-o dinhi. Ingon usa ka sangputanan, nakakuha kami mga bracket alang sa mga bracket. Dili musugot? Dayon paghulat sa higayon nga ang abstraction sa database magsugod sa pagtulo ug magsugod ka sa pagpakig-away sa function (raw-sql)

Busa unsa ang akong buhaton? Ibilin nato ang SQL isip regular nga SQL - usa ka file kada hangyo:

-- name: users-by-country
select *
  from users
 where country_code = :country_code

... ug dayon basaha kini nga file, himoon kini nga regular nga Clojure function:

(defqueries "some/where/users_by_country.sql"
   {:connection db-spec})

;;; A function with the name `users-by-country` has been created.
;;; Let's use it:
(users-by-country {:country_code "GB"})
;=> ({:name "Kris" :country_code "GB" ...} ...)

Pinaagi sa pagsunod sa "SQL sa iyang kaugalingon, Clojure sa iyang kaugalingon" nga prinsipyo, imong makuha:

  • Walay syntactic surprises. Ang imong database (sama sa uban pa) dili 100% nga nagsunod sa sukaranan sa SQL - apan dili kini hinungdanon alang sa Yesql. Dili ka mag-usik sa oras sa pagpangita alang sa mga gimbuhaton nga adunay katumbas nga syntax sa SQL. Dili na nimo kinahanglan nga mobalik sa usa ka function (raw-sql "pipila ('funky'::SYNTAX)")).
  • Labing maayo nga suporta sa editor. Ang imong editor adunay maayo kaayo nga suporta sa SQL. Pinaagi sa pagtipig sa SQL ingon SQL mahimo ra nimo kini gamiton.
  • Pagkaangay sa team. Ang imong mga DBA makabasa ug makasulat sa SQL nga imong gigamit sa imong proyekto sa Clojure.
  • Mas sayon ​​nga performance tuning. Kinahanglan ba nga maghimo usa ka plano alang sa usa ka problema nga pangutana? Dili kini problema kung ang imong pangutana kay regular nga SQL.
  • Paggamit pag-usab sa mga pangutana. I-drag ug ihulog ang parehas nga mga file sa SQL sa ubang mga proyekto tungod kay kini yano ra nga karaan nga SQL - ipaambit lang kini.

Sa akong opinyon, ang ideya cool kaayo ug sa samang higayon yano kaayo, salamat nga ang proyekto nakakuha og daghan mga sumusunod sa lain-laing mga pinulongan. Ug sunod natong sulayan ang paggamit sa susamang pilosopiya sa pagbulag sa SQL code gikan sa tanang butang nga layo pa sa ORM.

Mga tagdumala sa IDE ug DB

Magsugod ta sa usa ka yano nga buluhaton matag adlaw. Kasagaran kinahanglan naton pangitaon ang pipila ka mga butang sa database, pananglitan, pangitaa ang usa ka lamesa sa schema ug tun-an ang istruktura niini (unsa nga mga kolum, mga yawe, mga indeks, mga pagpugong, ug uban pa ang gigamit). Ug gikan sa bisan unsang graphical nga IDE o gamay nga DB-manager, una sa tanan, gipaabut namon nga eksakto kini nga mga abilidad. Aron kini paspas ug dili ka maghulat tunga sa oras hangtod makuha ang usa ka bintana nga adunay kinahanglan nga kasayuran (ilabi na sa hinay nga koneksyon sa usa ka hilit nga database), ug sa parehas nga oras, ang kasayuran nga nadawat bag-o ug may kalabutan, ug dili cached junk. Dugang pa, kon mas komplikado ug mas dako ang database ug mas daghan ang gidaghanon niini, mas lisud ang pagbuhat niini.

Apan kasagaran akong ilabay ang mouse ug magsulat lang og code. Ingnon ta nga kinahanglan nimong mahibal-an kung unsang mga lamesa (ug kung unsang mga kabtangan) ang naa sa laraw sa "HR". Sa kadaghanan sa mga DBMS, ang gitinguha nga resulta mahimong makab-ot niining yano nga pangutana gikan sa information_schema:

select table_name
     , ...
  from information_schema.tables
 where schema = 'HR'

Gikan sa database ngadto sa database, ang mga sulod sa maong mga reference table managlahi depende sa kapabilidad sa matag DBMS. Ug, pananglitan, alang sa MySQL, gikan sa parehas nga reperensiya nga libro mahimo nimong makuha ang mga parameter sa lamesa nga piho sa kini nga DBMS:

select table_name
     , storage_engine -- Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ "Π΄Π²ΠΈΠΆΠΎΠΊ" ("MyISAM", "InnoDB" etc)
     , row_format     -- Π€ΠΎΡ€ΠΌΠ°Ρ‚ строки ("Fixed", "Dynamic" etc)
     , ...
  from information_schema.tables
 where schema = 'HR'

Ang Oracle wala mahibalo sa information_schema, apan aduna kini Oracle metadata, ug walay dagkong problema nga mitungha:

select table_name
     , pct_free       -- ΠœΠΈΠ½ΠΈΠΌΡƒΠΌ свободного мСста Π² Π±Π»ΠΎΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… (%)
     , pct_used       -- ΠœΠΈΠ½ΠΈΠΌΡƒΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠΎΠ³ΠΎ мСста Π² Π±Π»ΠΎΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… (%)
     , last_analyzed  -- Π”Π°Ρ‚Π° послСднСго сбора статистики
     , ...
  from all_tables
 where owner = 'HR'

Ang ClickHouse walay eksepsiyon:

select name
     , engine -- Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ "Π΄Π²ΠΈΠΆΠΎΠΊ" ("MergeTree", "Dictionary" etc)
     , ...
  from system.tables
 where database = 'HR'

Ang susamang butang mahimo sa Cassandra (nga adunay mga columnfamilies imbes nga mga lamesa ug mga keyspace imbes nga mga eskema):

select columnfamily_name
     , compaction_strategy_class  -- БтратСгия сборки мусора
     , gc_grace_seconds           -- ВрСмя ΠΆΠΈΠ·Π½ΠΈ мусора
     , ...
  from system.schema_columnfamilies
 where keyspace_name = 'HR'

Alang sa kadaghanan sa ubang mga database, mahimo ka usab makahimo og parehas nga mga pangutana (bisan ang Mongo adunay espesyal nga sistema sa pagkolekta, nga adunay kasayuran bahin sa tanan nga mga koleksyon sa sistema).

Siyempre, niining paagiha makakuha ka og impormasyon dili lamang mahitungod sa mga lamesa, kondili mahitungod sa bisan unsang butang sa kinatibuk-an. Matag karon ug unya, ang buotan nga mga tawo mopaambit sa maong code alang sa lain-laing mga database, sama pananglit, sa sunod-sunod nga mga artikulo sa habra nga β€œFunctions for documenting PostgreSQL databases” (Si Ayb, Si Ben, gym). Siyempre, ang pagtipig niining tibuok nga bukid sa mga pangutana sa akong ulo ug kanunay nga pag-type niini usa ka kalipay, mao nga sa akong paborito nga IDE / editor ako adunay usa ka pre-andam nga hugpong sa mga snippet alang sa kanunay nga gigamit nga mga pangutana, ug ang nahabilin mao ang pag-type sa mga ngalan sa butang sa template.

Ingon usa ka sangputanan, kini nga pamaagi sa pag-navigate ug pagpangita sa mga butang labi ka dali, makatipig daghang oras, ug gitugotan ka nga makuha ang eksakto nga kasayuran sa porma diin kini kinahanglan karon (sama, pananglitan, gihulagway sa post. "Pag-eksport sa datos gikan sa usa ka database sa bisan unsang format: unsa ang mahimo sa mga IDE sa IntelliJ nga plataporma").

Mga operasyon nga adunay mga butang

Human nato makit-an ug matun-an ang gikinahanglan nga mga butang, panahon na sa pagbuhat og butang nga mapuslanon niini. Natural, usab nga wala pagkuha sa imong mga tudlo sa keyboard.

Dili kini sekreto nga ang pagtangtang sa usa ka lamesa parehas ra tan-awon sa halos tanan nga mga database:

drop table hr.persons

Apan sa paghimo sa lamesa kini nahimong mas makapaikag. Halos bisan unsang DBMS (lakip ang daghang NoSQL) mahimong "makahimo ug lamesa" sa usa ka porma o lain, ug ang panguna nga bahin niini magkalainlain bisan gamay (ngalan, lista sa mga kolum, mga tipo sa datos), apan ang ubang mga detalye mahimong lahi kaayo ug magdepende sa internal device ug mga kapabilidad sa usa ka piho nga DBMS. Ang akong paborito nga pananglitan mao nga sa dokumentasyon sa Oracle adunay mga "hubo" nga BNF alang sa syntax nga "paghimo lamesa" nag-okupar ug 31 ka panid. Ang ubang mga DBMS adunay mas kasarangan nga kapabilidad, apan ang matag usa niini adunay daghang makapaikag ug talagsaon nga mga bahin alang sa paghimo sa mga lamesa (postgres, MySQL, ipis, cassandra). Dili tingali nga ang bisan unsang graphical nga "wizard" gikan sa laing IDE (ilabi na ang usa ka unibersal) makahimo sa hingpit nga pagtabon sa tanan niini nga mga abilidad, ug bisan kung mahimo, dili kini usa ka talan-awon alang sa mga naluya sa kasingkasing. Sa samang higayon, usa ka husto ug tukma sa panahon nga sinulat nga pahayag paghimo og lamesa magtugot kanimo sa dali nga paggamit sa tanan niini, paghimo sa pagtipig ug pag-access sa imong data nga kasaligan, kamalaumon ug komportable kutob sa mahimo.

Usab, daghang mga DBMS adunay ilang kaugalingon nga piho nga mga tipo sa mga butang nga wala magamit sa ubang mga DBMS. Dugang pa, makahimo kami og mga operasyon dili lamang sa mga butang sa database, kondili usab sa DBMS mismo, pananglitan, "pagpatay" sa usa ka proseso, pagpahigawas sa pipila ka lugar sa panumduman, pagpagana sa pagsubay, pagbalhin ngadto sa "read only" mode, ug daghan pa.

Karon magdibuho kita og gamay

Usa sa labing kasagaran nga mga buluhaton mao ang paghimo og usa ka diagram nga adunay mga butang sa database ug makita ang mga butang ug mga koneksyon tali kanila sa usa ka matahum nga litrato. Halos bisan unsang graphical IDE, bulag nga "command line" nga mga utilities, espesyal nga mga himan sa grapiko ug mga tigmodelo makahimo niini. Magdrowing sila og usa ka butang alang kanimo "kutob sa ilang mahimo," ug mahimo nimo nga maimpluwensyahan kini nga proseso gamay lamang sa tabang sa pipila ka mga parameter sa configuration file o mga checkbox sa interface.

Apan kini nga problema masulbad nga mas simple, mas flexible ug elegante, ug siyempre sa tabang sa code. Aron makahimo og mga diagram sa bisan unsang pagkakomplikado, kami adunay daghang mga espesyal nga markup nga mga pinulongan (DOT, GraphML ug uban pa), ug alang kanila usa ka bug-os nga pagkatibulaag sa mga aplikasyon (GraphViz, PlantUML, Mermaid) nga makabasa sa ingon nga mga panudlo ug mahanduraw kini sa lainlaing mga format. . Aw, nahibal-an na nato kung unsaon pagkuha og impormasyon mahitungod sa mga butang ug mga koneksyon tali kanila.

Ania ang usa ka gamay nga pananglitan kung unsa ang hitsura niini, gamit ang PlantUML ug demo database para sa PostgreSQL (sa wala mao ang usa ka SQL query nga makamugna sa gikinahanglan nga instruksyon alang sa PlantUML, ug sa tuo mao ang resulta):

"Database as Code" nga Kasinatian

select '@startuml'||chr(10)||'hide methods'||chr(10)||'hide stereotypes' union all
select distinct ccu.table_name || ' --|> ' ||
       tc.table_name as val
  from table_constraints as tc
  join key_column_usage as kcu
    on tc.constraint_name = kcu.constraint_name
  join constraint_column_usage as ccu
    on ccu.constraint_name = tc.constraint_name
 where tc.constraint_type = 'FOREIGN KEY'
   and tc.table_name ~ '.*' union all
select '@enduml'

Ug kung mosulay ka gamay, unya gibase sa ER template para sa PlantUML makakuha ka og butang nga susama kaayo sa tinuod nga ER diagram:

Ang pangutana sa SQL usa ka gamay nga mas komplikado

-- Π¨Π°ΠΏΠΊΠ°
select '@startuml
        !define Table(name,desc) class name as "desc" << (T,#FFAAAA) >>
        !define primary_key(x) <b>x</b>
        !define unique(x) <color:green>x</color>
        !define not_null(x) <u>x</u>
        hide methods
        hide stereotypes'
 union all
-- Π’Π°Π±Π»ΠΈΡ†Ρ‹
select format('Table(%s, "%s n information about %s") {'||chr(10), table_name, table_name, table_name) ||
       (select string_agg(column_name || ' ' || upper(udt_name), chr(10))
          from information_schema.columns
         where table_schema = 'public'
           and table_name = t.table_name) || chr(10) || '}'
  from information_schema.tables t
 where table_schema = 'public'
 union all
-- Бвязи ΠΌΠ΅ΠΆΠ΄Ρƒ Ρ‚Π°Π±Π»ΠΈΡ†Π°ΠΌΠΈ
select distinct ccu.table_name || ' "1" --> "0..N" ' || tc.table_name || format(' : "A %s may haven many %s"', ccu.table_name, tc.table_name)
  from information_schema.table_constraints as tc
  join information_schema.key_column_usage as kcu on tc.constraint_name = kcu.constraint_name
  join information_schema.constraint_column_usage as ccu on ccu.constraint_name = tc.constraint_name
 where tc.constraint_type = 'FOREIGN KEY'
   and ccu.constraint_schema = 'public'
   and tc.table_name ~ '.*'
 union all
-- Подвал
select '@enduml'

"Database as Code" nga Kasinatian

Kung tan-awon nimo pag-ayo, sa ilawom sa hood daghang mga gamit sa paghanduraw ang naggamit usab parehas nga mga pangutana. Tinuod, kini nga mga hangyo kasagarang lawom "hardwired" sa code sa aplikasyon mismo ug lisud sabton, wala pay labot ang bisan unsang kausaban niini.

Sukatan ug pagmonitor

Mopadayon kita sa usa ka tradisyonal nga komplikado nga hilisgutan - pag-monitor sa performance sa database. Nakahinumdom ko og gamay nga tinuod nga istorya nga gisulti kanako sa β€œusa sa akong mga higala.” Sa laing proyekto adunay nagpuyo nga usa ka gamhanan nga DBA, ug pipila sa mga developers nakaila kaniya sa personal, o nakakita kaniya sa personal (bisan pa sa kamatuoran nga, sumala sa mga hungihong, siya nagtrabaho sa usa ka dapit sa sunod nga bilding) . Sa oras nga "X", sa dihang ang sistema sa poduction sa usa ka dako nga retailer nagsugod na usab sa "mobati nga dili maayo" sa makausa pa, siya hilom nga nagpadala sa mga screenshot sa mga graph gikan sa Oracle Enterprise Manager, diin iyang maampingon nga gipasiugda ang mga kritikal nga mga dapit nga adunay pula nga marka alang sa "comprehensibility" ( kini, sa gamay nga pagkabutang, wala kaayo makatabang). Ug base sa kini nga "photo card" kinahanglan nako nga pagtratar. Sa samang higayon, walay usa nga adunay access sa bililhon (sa duha ka mga pagbati sa pulong) Enterprise Manager, tungod kay Ang sistema komplikado ug mahal, sa kalit "ang mga nag-develop napandol sa usa ka butang ug gibuak ang tanan." Busa, ang mga developer "empirically" nakit-an ang lokasyon ug hinungdan sa mga preno ug gipagawas ang usa ka patch. Kung ang mahulgaon nga sulat gikan sa DBA dili na moabut pag-usab sa umaabot nga umaabot, nan ang tanan makaginhawa sa kahupayan ug mobalik sa ilang mga buluhaton karon (hangtod sa bag-ong Sulat).

Apan ang proseso sa pag-monitor mahimong tan-awon nga labi ka makalingaw ug mahigalaon, ug labing hinungdanon, dali ma-access ug transparent alang sa tanan. Labing menos ang sukaranan nga bahin niini, ingon usa ka pagdugang sa mga nag-unang sistema sa pag-monitor (nga siguradong mapuslanon ug sa daghang mga kaso dili mapulihan). Ang bisan unsang DBMS gawasnon ug hingpit nga walay bayad sa pagpaambit sa impormasyon bahin sa kasamtangang kahimtang ug performance niini. Sa parehas nga "dugo" nga Oracle DB, hapit bisan unsang kasayuran bahin sa pasundayag makuha gikan sa mga pagtan-aw sa sistema, gikan sa mga proseso ug sesyon hangtod sa kahimtang sa buffer cache (pananglitan, Mga script sa DBA, seksyon nga "Pag-monitor"). Ang Postgresql usab adunay usa ka bug-os nga hugpong sa mga pagtan-aw sa sistema alang sa pagmonitor sa database, ilabina kadtong gikinahanglan sa adlaw-adlaw nga kinabuhi sa bisan unsang DBA, sama sa pg_stat_activity, pg_stat_database, pg_stat_bgwriter. Ang MySQL bisan adunay usa ka lahi nga schema alang niini. performance_schema. Usa ka In Mongo built-in profiler nag-aggregate sa performance data ngadto sa usa ka system collection sistema.profile.

Busa, armado sa usa ka matang sa metrics collector (Telegraf, Metricbeat, Collectd) nga makahimo sa custom sql query, usa ka storage niini nga mga metrics (InfluxDB, Elasticsearch, Timescaledb) ug usa ka visualizer (Grafana, Kibana), mahimo ka nga makakuha og usa ka sayon ​​​​nga paagi. ug usa ka flexible monitoring system nga hugot nga i-integrate sa uban nga system-wide metrics (makuha, pananglitan, gikan sa application server, gikan sa OS, ug uban pa). Sama pananglit, gihimo kini sa pgwatch2, nga gigamit ang kombinasyon sa InfluxDB + Grafana ug usa ka hugpong sa mga pangutana sa mga pagtan-aw sa sistema, nga mahimo usab nga ma-access. idugang ang naandan nga mga pangutana.

Total

Ug kini usa lamang ka gibanabana nga lista kung unsa ang mahimo sa among database gamit ang regular nga SQL code. Sigurado ako nga makit-an nimo ang daghang mga gamit, isulat sa mga komento. Ug maghisgot kami kung giunsa (ug labing hinungdanon kung ngano) aron ma-automate kining tanan ug ilakip kini sa imong pipeline sa CI / CD sa sunod nga higayon.

Source: www.habr.com

Idugang sa usa ka comment