"Databank as koade"-ûnderfining

"Databank as koade"-ûnderfining

SQL, wat kin ienfâldiger wêze? Elk fan ús kin in ienfâldich fersyk skriuwe - wy typen útkieze, list de fereaske kolommen, dan fan, tabel namme, guon betingsten yn wêr en dat is alles - nuttige gegevens binne yn ús bûse, en (hast) nettsjinsteande hokker DBMS op dat stuit ûnder de motorkap is (of miskien hielendal gjin DBMS). As gefolch, wurkje mei hast alle gegevens boarne (relasjoneel en net sa) kin beskôge wurde út it eachpunt fan gewoane koade (mei alles wat it ymplisearret - ferzje kontrôle, koade review, statyske analyze, autotests, en dat is alles). En dit jildt net allinich foar de gegevens sels, skema's en migraasjes, mar yn 't algemien foar it heule libben fan' e opslach. Yn dit artikel sille wy prate oer deistige taken en problemen fan wurkjen mei ferskate databases ûnder de lens fan "database as koade".

En lit ús begjinne rjocht fan ORM. De earste fjildslaggen fan it type "SQL vs ORM" waarden werom opmurken pre-Petrine Rus'.

Objekt-relasjonele mapping

ORM-supporters wurdearje tradisjoneel snelheid en gemak fan ûntwikkeling, ûnôfhinklikens fan 'e DBMS en skjinne koade. Foar in protte fan ús is de koade foar it wurkjen mei de databank (en faaks de databank sels)

it sjocht der meastentiids sa út...

@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;
    }
  ...

It model wurdt ophongen mei tûke annotaasjes, en earne efter de skermen genereart en útfiert in dappere ORM tonnen wat SQL-koade. Trouwens, ûntwikkelders besykje har bêst om harsels te isolearjen fan har database mei kilometers oan abstraksjes, wat oanjout op guon "SQL hate".

Oan 'e oare kant fan' e barrikaden notearje oanhingers fan suver "hânmakke" SQL de mooglikheid om al it sap út har DBMS te drukken sûnder ekstra lagen en abstraksjes. Dêrtroch ferskine "data-sintraal" projekten, wêrby't spesjaal oplaat minsken belutsen binne by de databank (se binne ek "basicists", se binne ek "basicists", se binne ek "basdeners", ensfh.), En de ûntwikkelders allinne moatte "lûke" de klear makke werjeften en opslein prosedueres, sûnder yn te gean yn details.

Wat as wy it bêste fan beide wrâlden hiene? Hoe dit wurdt dien yn in prachtich ark mei in libben-befêstigjende namme Yesql. Ik sil in pear rigels út it algemiene konsept jaan yn myn fergese oersetting, en jo kinne der yn mear detail mei yn 'e kunde komme hjir.

Clojure is in koele taal foar it meitsjen fan DSLs, mar SQL sels is in koele DSL, en wy hawwe net nedich in oar. S-útdrukkingen binne geweldich, mar se foegje hjir neat nij ta. As gefolch krije wy heakjes om 'e heakjes. Net mei iens? Wachtsje dan op it momint dat de abstraksje oer de databank begjint te lekken en jo begjinne te fjochtsjen mei de funksje (raw-sql)

Dus wat moat ik dwaan? Litte wy SQL litte as gewoane SQL - ien bestân per fersyk:

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

... en lês dan dit bestân, en feroaret it yn in gewoane Clojure-funksje:

(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" ...} ...)

Troch te folgjen oan it prinsipe "SQL troch himsels, Clojure troch himsels", krije jo:

  • Gjin syntaktyske ferrassingen. Jo databank (lykas elke oare) is net 100% konform mei de SQL-standert - mar dit makket neat út foar Yesql. Jo sille noait tiid fergrieme op jacht nei funksjes mei SQL-lykweardige syntaksis. Jo sille nea hoege werom nei in funksje (raw-sql "some('funky'::SYNTAX)")).
  • Bêste bewurker stipe. Jo bewurker hat al poerbêste SQL-stipe. Troch SQL te bewarjen as SQL kinne jo it gewoan brûke.
  • Team komptabiliteit. Jo DBA's kinne de SQL lêze en skriuwe dy't jo brûke yn jo Clojure-projekt.
  • Makliker prestaasje tuning. Moatte in plan bouwe foar in problematyske fraach? Dit is gjin probleem as jo query gewoane SQL is.
  • Opnij brûke queries. Sleep en drop deselde SQL-bestannen yn oare projekten, om't it gewoan âlde SQL is - diel it gewoan.

Yn myn miening is it idee heul cool en tagelyk heul ienfâldich, wêrtroch't it projekt in protte opdien hat folgers yn in ferskaat oan talen. En wy sille neist besykje in ferlykbere filosofy oan te passen fan it skieden fan SQL-koade fan al it oare fier bûten de ORM.

IDE & DB behearders

Litte wy begjinne mei in ienfâldige deistige taak. Faak moatte wy sykje foar guon objekten yn 'e databank, bygelyks, fine in tabel yn it skema en studearje syn struktuer (wat kolommen, kaaien, yndeksen, beheinings, ensfh wurde brûkt). En fan elke grafyske IDE as in bytsje DB-manager ferwachtsje wy earst dizze kapasiteiten. Sadat it fluch is en jo net in healoere hoege te wachtsjen oant in finster mei de nedige ynformaasje tekene wurdt (benammen mei in trage ferbining mei in databank op ôfstân), en tagelyk de ûntfongen ynformaasje fris en relevant is, en net cache junk. Boppedat, hoe komplekser en grutter de databank en hoe grutter it oantal, hoe dreger it is om dit te dwaan.

Mar meastal smyt ik de mûs fuort en skriuw gewoan koade. Litte wy sizze dat jo moatte útfine hokker tabellen (en mei hokker eigenskippen) binne befette yn it "HR" skema. Yn 'e measte DBMS's kin it winske resultaat berikt wurde mei dizze ienfâldige query fan information_schema:

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

Fan databank nei databank ferskilt de ynhâld fan sokke referinsjetabellen ôfhinklik fan de mooglikheden fan elke DBMS. En, bygelyks, foar MySQL, út itselde referinsjeboek kinne jo tabelparameters krije spesifyk foar dit DBMS:

select table_name
     , storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
     , row_format     -- Формат строки ("Fixed", "Dynamic" etc)
     , ...
  from information_schema.tables
 where schema = 'HR'

Oracle wit net information_schema, mar it hat Oracle metadata, en gjin grutte problemen ûntsteane:

select table_name
     , pct_free       -- Минимум свободного места в блоке данных (%)
     , pct_used       -- Минимум используемого места в блоке данных (%)
     , last_analyzed  -- Дата последнего сбора статистики
     , ...
  from all_tables
 where owner = 'HR'

ClickHouse is gjin útsûndering:

select name
     , engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
     , ...
  from system.tables
 where database = 'HR'

Iets fergelykber kin dien wurde yn Cassandra (dy't kolomfamyljes hat ynstee fan tabellen en kaaispaasjes ynstee fan skema's):

select columnfamily_name
     , compaction_strategy_class  -- Стратегия сборки мусора
     , gc_grace_seconds           -- Время жизни мусора
     , ...
  from system.schema_columnfamilies
 where keyspace_name = 'HR'

Foar de measte oare databases kinne jo ek mei ferlykbere fragen komme (sels Mongo hat spesjale systeem kolleksje, dy't ynformaasje befettet oer alle kolleksjes yn it systeem).

Fansels kinne jo op dizze manier ynformaasje krije net allinich oer tabellen, mar oer elk objekt yn 't algemien. Fan tiid ta tiid diele freonlike minsken sokke koade foar ferskate databases, lykas, bygelyks, yn 'e searje fan habra-artikels "Funksjes foar it dokumintearjen fan PostgreSQL-databases" (Ayb, Ben, sportskoalle). Fansels is it sa'n genot om dizze hiele berch oanfragen yn myn holle te hâlden en se konstant te typen, dus yn myn favorite IDE/bewurker haw ik in foarbereide set snippets foar faak brûkte fragen, en alles wat oerbliuwt is it typen fan de objektnammen yn it sjabloan.

As resultaat is dizze metoade foar it navigearjen en sykjen nei objekten folle fleksibeler, besparret in protte tiid, en lit jo krekt de ynformaasje krije yn 'e foarm wêryn't it no nedich is (lykas bygelyks beskreaun yn 'e post "Gegevens eksportearje fan in databank yn elk formaat: wat IDE's kinne dwaan op it IntelliJ-platfoarm").

Operaasje mei objekten

Nei't wy de nedige objekten hawwe fûn en studearre, is it tiid om der wat nuttichs mei te dwaan. Fansels, ek sûnder jo fingers fan it toetseboerd te heljen.

It is gjin geheime dat it gewoan wiskjen fan in tabel itselde sil sjen yn hast alle databases:

drop table hr.persons

Mar mei it meitsjen fan 'e tafel wurdt it nijsgjirriger. Hast elke DBMS (ynklusyf in protte NoSQL) kin "tabel oanmeitsje" yn ien of oare foarm, en it haaddiel dêrfan sil sels in bytsje ferskille (namme, list mei kolommen, gegevenstypen), mar oare details kinne dramatysk ferskille en ôfhingje fan 'e ynterne apparaat en mooglikheden fan in spesifike DBMS. Myn favorite foarbyld is dat yn 'e Oracle-dokumintaasje d'r allinich "neaken" BNF's binne foar de syntaksis "tabel oanmeitsje" besette 31 siden. Oare DBMS's hawwe beskiedener mooglikheden, mar elk fan har hat ek in protte nijsgjirrige en unike funksjes foar it meitsjen fan tabellen (postgres, MySQL, kakkerlak, kassandra). It is net wierskynlik dat elke grafyske "wizard" fan in oare IDE (benammen in universele) al dizze kapasiteiten folslein kin dekke, en sels as it kin, sil it gjin spektakel wêze foar swakkens. Tagelyk in korrekt en op 'e tiid skreaune ferklearring meitsje tabel sil tastean jo te maklik brûke allegearre, meitsje opslach en tagong ta jo gegevens betrouber, optimaal en sa noflik mooglik.

Ek hawwe in protte DBMS's har eigen spesifike soarten objekten dy't net beskikber binne yn oare DBMS's. Boppedat kinne wy ​​​​operaasjes net allinich útfiere op databankobjekten, mar ek op 'e DBMS sels, bygelyks in proses "deadzje", wat ûnthâldgebiet frijmeitsje, tracing ynskeakelje, oerskeakelje nei "allinich lêze" modus, en folle mear.

No litte wy in bytsje tekenje

Ien fan 'e meast foarkommende taken is om in diagram te bouwen mei databankobjekten en de objekten en ferbiningen tusken har te sjen yn in prachtige foto. Hast elke grafyske IDE, aparte "kommandoline" nutsbedriuwen, spesjalisearre grafyske ark en modelers kinne dit dwaan. Se sille wat foar jo tekenje "sa goed as se kinne", en jo kinne dit proses in bytsje beynfloedzje allinich mei help fan in pear parameters yn it konfiguraasjetriem of karfakjes yn 'e ynterface.

Mar dit probleem kin oplost wurde folle ienfâldiger, fleksibeler en elegant, en fansels mei help fan koade. Om diagrammen fan elke kompleksiteit te meitsjen, hawwe wy ferskate spesjalisearre opmaaktalen (DOT, GraphML ensfh), en foar har in heule fersprieding fan applikaasjes (GraphViz, PlantUML, Mermaid) dy't sokke ynstruksjes kinne lêze en visualisearje yn in ferskaat oan formaten . No, wy witte al hoe't jo ynformaasje kinne krije oer objekten en ferbiningen tusken har.

Hjir is in lyts foarbyld fan hoe't dit der útsjen kin, mei PlantUML en demo databank foar PostgreSQL (links is in SQL-query dy't de fereaske ynstruksje foar PlantUML sil generearje, en rjochts is it resultaat):

"Databank as koade"-ûnderfining

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'

En as jo besykje in bytsje, dan basearre op ER sjabloan foar PlantUML jo kinne wat krije dat heul gelyk is oan in echte ER-diagram:

De SQL-query is in bytsje komplisearre

-- Шапка
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'

"Databank as koade"-ûnderfining

As jo ​​​​nau sjogge, brûke in protte fisualisaasjeark ûnder de kap ek ferlykbere fragen. Wier, dizze oanfragen binne meastal djip "hardwired" yn 'e koade fan' e applikaasje sels en binne lestich te begripen, om gjin wiziging fan har te hawwen.

Metriken en tafersjoch

Litte wy trochgean nei in tradisjoneel kompleks ûnderwerp - monitoring fan databankprestaasjes. Ik herinner my in lyts wier ferhaal dat my ferteld waard troch "ien fan myn freonen." Op in oar projekt wenne in bepaalde krêftige DBA, en in pear fan 'e ûntwikkelders wisten him persoanlik, of hienen him oait persoanlik sjoen (nettsjinsteande it feit dat hy, neffens geroften, earne yn it folgjende gebou wurke). Op oere "X", doe't it poduksjesysteem fan in grutte retailer opnij begon te "min te fielen", stjoerde hy stil skermôfbyldings fan grafiken fan Oracle Enterprise Manager, wêrop hy krityske plakken foarsichtich markearre mei in reade marker foar "begryplikens" ( dit, om it myld te sizzen, hat net folle holpen). En op basis fan dizze "fotokaart" moast ik behannelje. Tagelyk hie gjinien tagong ta de kostbere (yn beide betsjuttingen fan it wurd) Enterprise Manager, om't it systeem is kompleks en djoer, ynienen "de ûntwikkelders stroffelje oer wat en brekke alles." Dêrom hawwe de ûntwikkelders "empirysk" de lokaasje en oarsaak fan 'e remmen fûn en in patch frijlitten. As de driigjende brief fan de DBA yn de heine takomst net wer oankaam, dan soe elkenien in suchtsje fan opluchting sykhelje en weromgean nei har hjoeddeistige taken (oant de nije Brief).

Mar it tafersjochproses kin leuker en freonliker útsjen, en it wichtichste, tagonklik en transparant foar elkenien. Op syn minst it basisdiel, as tafoeging oan 'e wichtichste monitoaringssystemen (dy't wis nuttich binne en yn in protte gefallen ûnferfangber binne). Elke DBMS is frij en absolút fergees om ynformaasje te dielen oer syn hjoeddeistige steat en prestaasjes. Yn deselde "bloedige" Oracle DB kin hast alle ynformaasje oer prestaasjes wurde krigen fan systeemwerjeften, fariearjend fan prosessen en sesjes oant de tastân fan 'e buffer-cache (bygelyks, DBA Skripten, seksje "Monitoring"). Postgresql hat ek in hiele bosk systeem werjeften foar databank monitoring, benammen dyjingen dy't ûnmisber binne yn it deistich libben fan elke DBA, lykas pg_stat_activity, pg_stat_database, pg_stat_bgwriter. MySQL hat sels in apart skema foar dit. performance_skema. A Yn Mongo ynboude profiler aggregearret prestaasjesgegevens yn in systeemkolleksje system.profyl.

Sa kinne jo, bewapene mei in soarte fan metriken-samler (Telegraf, Metricbeat, Collectd) dy't oanpaste sql-fragen kinne útfiere, in opslach fan dizze metriken (InfluxDB, Elasticsearch, Timescaledb) en in visualizer (Grafana, Kibana), kinne jo in frij maklik krije en in fleksibele monitoaring systeem dat sil wurde nau yntegrearre mei oare systeem-wide metriken (ferkrigen, bygelyks, fan de applikaasje tsjinner, út it OS, ensfh). As, bygelyks, dit wurdt dien yn pgwatch2, dy't de kombinaasje InfluxDB + Grafana brûkt en in set fan queries nei systeemwerjeften, dy't ek tagonklik binne tafoegje oanpaste queries.

Totaal

En dit is mar in ûngefear list fan wat kin wurde dien mei ús databank mei help fan reguliere SQL-koade. Ik bin der wis fan dat jo in protte mear gebrûk kinne fine, skriuw yn 'e kommentaren. En wy sille prate oer hoe (en it wichtichste wêrom) dit alles automatisearje en it folgjende kear yn jo CI / CD-pipeline opnimme.

Boarne: www.habr.com

Add a comment