Upplifun af „gagnagrunni sem kóða“

Upplifun af „gagnagrunni sem kóða“

SQL, hvað gæti verið einfaldara? Hvert okkar getur skrifað einfalda beiðni - við skrifum velja, skráðu þá dálka sem þarf, síðan frá, nafn töflu, nokkur skilyrði í þar sem og það er allt - gagnleg gögn eru í vasa okkar og (næstum) óháð því hvaða DBMS er undir hettunni á þeim tíma (eða kannski alls ekki DBMS). Þar af leiðandi er hægt að líta á vinnu með nánast hvaða gagnagjafa sem er (tengt og ekki) frá sjónarhóli venjulegs kóða (með öllu því sem það felur í sér - útgáfustýringu, kóða endurskoðun, kyrrstöðugreining, sjálfvirk próf, og það er allt). Og þetta á ekki aðeins við um gögnin sjálf, skema og flutninga, heldur almennt um allt líf geymslunnar. Í þessari grein munum við tala um hversdagsleg verkefni og vandamál við að vinna með ýmsa gagnagrunna undir linsunni „gagnagrunnur sem kóða“.

Og við skulum byrja strax frá ORM. Tekið var eftir fyrstu bardögum af gerðinni „SQL vs ORM“ aftur inn Pre-Petrine Rus'.

Hlutatengslakortlagning

Stuðningsmenn ORM meta jafnan hraða og auðvelda þróun, sjálfstæði frá DBMS og hreinum kóða. Fyrir mörg okkar er kóðinn til að vinna með gagnagrunninn (og oft gagnagrunninn sjálfan)

þetta lítur yfirleitt eitthvað svona ú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;
    }
  ...

Líkanið er hengt með snjöllum athugasemdum og einhvers staðar á bak við tjöldin býr hraustur ORM til og framkvæmir tonn af SQL kóða. Við the vegur, verktaki reyna sitt besta til að einangra sig frá gagnagrunni sínum með kílómetra af útdrætti, sem bendir til nokkurra "SQL hata".

Hinum megin við hindrunina taka fylgismenn hreins „handgerðra“ SQL eftir hæfileikanum til að kreista allan safann úr DBMS þeirra án viðbótarlaga og útdráttar. Fyrir vikið birtast „gagnamiðuð“ verkefni þar sem sérþjálfað fólk tekur þátt í gagnagrunninum (þeir eru líka „basicists“, þeir eru líka „basicists“, þeir eru líka „basdeners“ o.s.frv.), og þróunaraðilarnir þarf aðeins að „draga“ tilbúnum skoðunum og geymdum verklagsreglum, án þess að fara í smáatriði.

Hvað ef við hefðum það besta af báðum heimum? Hvernig þetta er gert í dásamlegu tóli með nafni sem gefur líf Yesql. Ég mun gefa nokkrar línur frá almennu hugtakinu í frjálsu þýðingunni minni og þú getur kynnt þér það nánar hér.

Clojure er flott tungumál til að búa til DSL, en SQL sjálft er flott DSL og við þurfum ekki annað. S-tjáningar eru frábærar, en þær bæta engu nýju við hér. Fyrir vikið fáum við sviga vegna sviga. Ekki sammála? Bíddu svo eftir augnablikinu þegar útdrátturinn yfir gagnagrunninn byrjar að leka og þú byrjar að berjast við aðgerðina (raw-sql)

Svo hvað ætti ég að gera? Við skulum skilja SQL eftir sem venjulegan SQL - ein skrá fyrir hverja beiðni:

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

... og lestu síðan þessa skrá og breyttu henni í venjulega Clojure aðgerð:

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

Með því að fylgja "SQL út af fyrir sig, Clojure af sjálfu sér" meginreglunni færðu:

  • Ekkert setningafræðilegt á óvart. Gagnagrunnurinn þinn (eins og hver annar) er ekki 100% í samræmi við SQL staðalinn - en þetta skiptir ekki máli fyrir Yesql. Þú munt aldrei eyða tíma í að leita að aðgerðum með samsvarandi SQL setningafræði. Þú þarft aldrei að fara aftur í aðgerð (raw-sql "sum('funky'::SYNTAX)")).
  • Besti ritstjóri stuðningur. Ritstjórinn þinn hefur nú þegar framúrskarandi SQL stuðning. Með því að vista SQL sem SQL geturðu einfaldlega notað það.
  • Team eindrægni. DBAs þínir geta lesið og skrifað SQL sem þú notar í Clojure verkefninu þínu.
  • Auðveldari frammistöðustilling. Þarftu að búa til áætlun fyrir erfiða fyrirspurn? Þetta er ekki vandamál þegar fyrirspurnin þín er venjuleg SQL.
  • Endurnota fyrirspurnir. Dragðu og slepptu sömu SQL skrám í önnur verkefni vegna þess að það er bara venjulegt gamalt SQL - deildu því bara.

Hugmyndin er að mínu mati mjög flott og á sama tíma mjög einföld, því verkefnið hefur fengið marga fylgjendur á ýmsum tungumálum. Og við munum næst reyna að beita svipaðri hugmyndafræði að aðskilja SQL kóða frá öllu öðru langt fyrir utan ORM.

IDE & DB stjórnendur

Byrjum á einföldu hversdagsverki. Oft þurfum við að leita að einhverjum hlutum í gagnagrunninum, til dæmis finna töflu í skemanu og rannsaka uppbyggingu þess (hvaða dálkar, lyklar, vísitölur, skorður o.s.frv. eru notaðir). Og frá hvaða grafísku IDE eða litlum DB-stjóra, fyrst og fremst, búumst við við nákvæmlega þessum hæfileikum. Svo að það sé hratt og ekki þurfi að bíða í hálftíma þar til gluggi með nauðsynlegum upplýsingum er dreginn upp (sérstaklega með hægri tengingu við fjarlægan gagnagrunn) og á sama tíma eru upplýsingarnar sem berast ferskar og viðeigandi, og ekki rusl í skyndiminni. Þar að auki, því flóknari og stærri sem gagnagrunnurinn er og því fleiri sem þeir eru, því erfiðara er að gera þetta.

En yfirleitt hendi ég músinni og skrifa bara kóða. Segjum að þú þurfir að finna út hvaða töflur (og með hvaða eiginleikum) eru í "HR" skemanu. Í flestum DBMS er hægt að ná tilætluðum árangri með þessari einföldu fyrirspurn frá information_schema:

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

Frá gagnagrunni til gagnagrunns er innihald slíkra viðmiðunartafla mismunandi eftir getu hvers DBMS. Og, til dæmis, fyrir MySQL, úr sömu uppflettibók er hægt að fá töflubreytur sem eru sértækar fyrir þetta DBMS:

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

Oracle þekkir ekki information_schema, en það hefur það Oracle lýsigögn, og engin stór vandamál koma upp:

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

ClickHouse er engin undantekning:

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

Eitthvað svipað er hægt að gera í Cassandra (sem hefur dálkafjölskyldur í staðinn fyrir töflur og lyklarými í stað skemas):

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

Fyrir flesta aðra gagnagrunna geturðu líka komið með svipaðar fyrirspurnir (jafnvel Mongo hefur sérstakt kerfissöfnun, sem inniheldur upplýsingar um öll söfn í kerfinu).

Auðvitað, á þennan hátt geturðu fengið upplýsingar ekki aðeins um töflur, heldur um hvaða hlut sem er almennt. Af og til deilir vingjarnlegt fólk slíkum kóða fyrir mismunandi gagnagrunna, eins og til dæmis í röð habra greina „Functions for documenting PostgreSQL gagnagrunna“ (Ayb, Ben, líkamsræktarstöð). Auðvitað er svo ánægjulegt að hafa allt þetta fjall af fyrirspurnum í hausnum á mér og skrifa þær stöðugt, svo í uppáhalds IDE/ritlinum mínum er ég með fyrirfram útbúið sett af bútum fyrir oft notaðar fyrirspurnir, og allt sem er eftir er að slá inn hlutanöfn inn í sniðmátið.

Þess vegna er þessi aðferð við að fletta og leita að hlutum mun sveigjanlegri, sparar mikinn tíma og gerir þér kleift að fá nákvæmlega upplýsingarnar á því formi sem þær eru nauðsynlegar (eins og til dæmis lýst í færslunni "Að flytja út gögn úr gagnagrunni á hvaða sniði sem er: hvað IDEs geta gert á IntelliJ vettvangnum").

Aðgerðir með hluti

Eftir að við höfum fundið og rannsakað nauðsynlega hluti er kominn tími til að gera eitthvað gagnlegt við þá. Auðvitað, líka án þess að taka fingurna af lyklaborðinu.

Það er ekkert leyndarmál að einfaldlega að eyða töflu mun líta eins út í næstum öllum gagnagrunnum:

drop table hr.persons

En með stofnun borðsins verður það áhugaverðara. Næstum hvaða DBMS sem er (þar á meðal mörg NoSQL) getur „búið til töflu“ á einu eða öðru formi, og meginhluti hennar mun jafnvel vera örlítið frábrugðinn (nafn, listi yfir dálka, gagnategundir), en aðrar upplýsingar geta verið verulega mismunandi og fer eftir innra tæki og getu tiltekins DBMS. Uppáhalds dæmið mitt er að í Oracle skjölunum eru aðeins „naktir“ BNF fyrir setningafræði „búa til töflu“ taka 31 blaðsíðu. Aðrar DBMS hafa hóflegri getu, en hver þeirra hefur einnig marga áhugaverða og einstaka eiginleika til að búa til töflur (postgres, MySQL, kakkalakki, cassandra). Það er ólíklegt að einhver grafískur „töframaður“ frá öðrum IDE (sérstaklega alhliða) geti náð yfir alla þessa hæfileika að fullu, og jafnvel þótt það geti það, mun það ekki vera sjónarspil fyrir viðkvæma. Jafnframt rétt og tímanlega skrifuð yfirlýsing búa til töflu gerir þér kleift að nota þau öll á auðveldan hátt, gera geymslu og aðgang að gögnum þínum áreiðanlega, ákjósanlegasta og eins þægilega og mögulegt er.

Einnig hafa margar DBMS sínar eigin sérstakar gerðir af hlutum sem eru ekki tiltækar í öðrum DBMS. Þar að auki getum við framkvæmt aðgerðir ekki aðeins á gagnagrunnshlutum, heldur einnig á DBMS sjálfu, til dæmis, „drepið“ ferli, losað um minnissvæði, virkjað rakningu, skipt yfir í „read only“ ham og margt fleira.

Nú skulum við teikna aðeins

Eitt algengasta verkefnið er að smíða skýringarmynd með gagnagrunnshlutum og sjá hlutina og tengslin á milli þeirra í fallegri mynd. Næstum hvaða grafísku IDE, aðskilin „skipanalínu“ tól, sérhæfð grafísk verkfæri og módelmenn geta gert þetta. Þeir munu teikna eitthvað fyrir þig „eins og þeir geta“ og þú getur aðeins haft áhrif á þetta ferli með hjálp nokkurra breytu í stillingarskránni eða gátreitum í viðmótinu.

En þetta vandamál er hægt að leysa mun einfaldara, sveigjanlegra og glæsilegra, og auðvitað með hjálp kóða. Til að búa til skýringarmyndir af hvaða flóknu sem er, höfum við nokkur sérhæfð álagningarmál (DOT, GraphML o.s.frv.), og fyrir þau fjöldann allan af forritum (GraphViz, PlantUML, Mermaid) sem geta lesið slíkar leiðbeiningar og séð þær fyrir sér á ýmsum sniðum . Jæja, við vitum nú þegar hvernig á að fá upplýsingar um hluti og tengingar á milli þeirra.

Hér er lítið dæmi um hvernig þetta gæti litið út, með því að nota PlantUML og kynningargagnagrunnur fyrir PostgreSQL (vinstra megin er SQL fyrirspurn sem mun búa til nauðsynlegar leiðbeiningar fyrir PlantUML, og til hægri er niðurstaðan):

Upplifun af „gagnagrunni sem kóða“

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'

Og ef þú reynir aðeins, þá byggt á ER sniðmát fyrir PlantUML þú getur fengið eitthvað mjög svipað og alvöru ER skýringarmynd:

SQL fyrirspurnin er aðeins flóknari

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

Upplifun af „gagnagrunni sem kóða“

Ef þú lítur vel, undir hettunni nota mörg sjónræn verkfæri líka svipaðar fyrirspurnir. Að vísu eru þessar beiðnir yfirleitt djúpar „tengdur“ inn í kóða forritsins sjálfs og er erfitt að skilja, svo ekki sé minnst á breytingar á þeim.

Mælingar og eftirlit

Við skulum halda áfram að hefðbundnu flóknu efni - eftirlit með frammistöðu gagnagrunns. Ég man eftir lítilli sannri sögu sem „einn af vinum mínum“ sagði mér. Í öðru verkefni bjó ákveðinn öflugur DBA og fáir verktaki þekktu hann persónulega, eða höfðu nokkurn tíma séð hann í eigin persónu (þrátt fyrir að, samkvæmt sögusögnum, hafi hann unnið einhvers staðar í næstu byggingu). Á klukkutímanum „X“, þegar framleiðslukerfi stórs smásala fór að „líða illa“ enn og aftur, sendi hann hljóðlaust skjáskot af línuritum frá Oracle Enterprise Manager, þar sem hann auðkenndi vandlega mikilvæga staði með rauðu merki fyrir „skiljanleika“ ( þetta hjálpaði vægast sagt ekki mikið). Og miðað við þetta „myndakort“ þurfti ég að meðhöndla. Á sama tíma hafði enginn aðgang að hinum dýrmæta (í báðum merkingum orðsins) Enterprise Manager, vegna þess Kerfið er flókið og dýrt, skyndilega „rekasta verktaki á einhverju og brjóta allt“. Þess vegna fundu verktaki "reynslufræðilega" staðsetningu og orsök bremsanna og gáfu út plástur. Ef ógnarbréfið frá DBA kæmi ekki aftur á næstunni, þá myndu allir anda léttar og snúa aftur til núverandi verkefna (þar til nýja bréfsins).

En eftirlitsferlið getur litið skemmtilegra og vingjarnlegra út og síðast en ekki síst aðgengilegt og gagnsætt fyrir alla. Að minnsta kosti grunnhluti þess, sem viðbót við helstu vöktunarkerfi (sem eru vissulega gagnleg og í mörgum tilfellum óbætanleg). Sérhvert DBMS er frjálst og algerlega ókeypis til að deila upplýsingum um núverandi ástand og frammistöðu. Í sömu „blóðugu“ Oracle DB er hægt að nálgast næstum allar upplýsingar um frammistöðu úr kerfissýnum, allt frá ferlum og lotum til stöðu biðminni skyndiminni (td, DBA forskriftir, kafla "Vöktun"). Postgresql hefur líka fullt af kerfissýnum fyrir gagnagrunnseftirlit, sérstaklega þau sem eru ómissandi í daglegu lífi hvers kyns DBA, svo sem pg_stat_activity, pg_stat_gagnagrunnur, pg_stat_bgwriter. MySQL hefur meira að segja sérstakt skema fyrir þetta. frammistöðuskema. A In Mongo innbyggt prófílari safnar frammistöðugögnum í kerfissafn kerfisprófíl.

Þannig, vopnaður einhvers konar mæligildasafnara (Telegraf, Metricbeat, Collectd) sem getur framkvæmt sérsniðnar sql fyrirspurnir, geymslu á þessum mæligildum (InfluxDB, Elasticsearch, Timescaledb) og visualizer (Grafana, Kibana), geturðu fengið nokkuð auðvelt og sveigjanlegt eftirlitskerfi sem verður náið samþætt öðrum kerfisbundnum mæligildum (sem fæst td frá forritaþjóninum, frá stýrikerfinu osfrv.). Eins og til dæmis er þetta gert í pgwatch2, sem notar InfluxDB + Grafana samsetninguna og mengi fyrirspurna til kerfissýna, sem einnig er hægt að nálgast bæta við sérsniðnum fyrirspurnum.

Alls

Og þetta er aðeins áætlaður listi yfir það sem hægt er að gera með gagnagrunninum okkar með því að nota venjulegan SQL kóða. Ég er viss um að þú getur fundið miklu fleiri notkun, skrifaðu í athugasemdum. Og við munum tala um hvernig (og síðast en ekki síst hvers vegna) á að gera allt þetta sjálfvirkt og hafa það með í CI/CD leiðslunni þinni næst.

Heimild: www.habr.com

Bæta við athugasemd