Skúsenosti „Databáza ako Сode“.

Skúsenosti „Databáza ako Сode“.

SQL, čo môže byť jednoduchšie? Každý z nás môže napísať jednoduchú požiadavku – napíšeme vybrať, potom uveďte požadované stĺpce z, názov tabuľky, niekoľko podmienok v kde a to je všetko - užitočné údaje v našom vrecku a (takmer) bez ohľadu na to, ktorý DBMS je v tom čase pod kapotou (alebo možno vôbec nie DBMS). Výsledkom je, že prácu s takmer akýmkoľvek zdrojom údajov (relačným a nie) možno považovať z hľadiska bežného kódu (so všetkými dôsledkami - kontrola verzií, kontrola kódu, statická analýza, autotesty a to je všetko). A to platí nielen pre samotné dáta, schémy a migrácie, ale vo všeobecnosti pre celú životnosť úložiska. V tomto článku si povieme o každodenných úlohách a problémoch práce s rôznymi databázami v rámci „databáza ako kód“.

A začnime rovno s ORM. Prvé bitky ako "SQL vs ORM" boli videné späť predpetrovská Rus.

Objektové relačné mapovanie

Zástancovia ORM tradične oceňujú rýchlosť a jednoduchosť vývoja, nezávislosť od DBMS a čistotu kódu. Pre mnohých z nás je kód pre prácu s databázou (a často aj samotnou databázou)

zvyčajne to vyzerá takto...

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

Model je zabalený do šikovných anotácií a niekde v zákulisí statočný ORM generuje a spúšťa tony nejakého SQL kódu. Mimochodom, vývojári sa zo všetkých síl snažia izolovať od svojej databázy kilometrami abstrakcií, čo naznačuje "SQL nenávisti".

Na druhej strane barikády prívrženci čistého „ručného“-SQL poznamenávajú schopnosť vytlačiť všetku šťavu zo svojho DBMS bez ďalších vrstiev a abstrakcií. V dôsledku toho sa objavujú „data-centrické“ projekty, kde sú do databázy zapojení špeciálne vyškolení ľudia (tiež sú „základisti“, sú aj „základisti“, sú tiež „bastardi“ atď.) a vývojári iba musia „vytiahnuť“ hotové pohľady a uložené procedúry bez toho, aby zachádzali do detailov.

A čo keď si vezmete to najlepšie z oboch svetov? Ako sa to robí v nádhernom nástroji s názvom, ktorý potvrdzuje život Yesql. Pár riadkov zo všeobecného konceptu uvediem vo svojom voľnom preklade a vy sa s ním môžete bližšie zoznámiť tu.

Clojure je skvelý jazyk na vytváranie DSL, ale samotný SQL je skvelý DSL a nepotrebujeme ďalší. S-výrazy sú skvelé, ale nepridávajú tu nič nové. V dôsledku toho dostaneme zátvorky kvôli zátvorkám. Nesúhlas? Potom počkajte na moment, kedy unikne abstrakcia nad databázou, a začnete s funkciou bojovať (raw-sql)

A čo robiť? Nechajme SQL ako normálny SQL – jeden súbor na požiadavku:

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

...a potom si prečítajte tento súbor a premeňte ho na bežnú funkciu Clojure:

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

Dodržaním zásady „SQL oddelené, Clojure oddelené“ získate:

  • Žiadne syntaktické prekvapenia. Vaša databáza (ako každá iná) nie je 100% kompatibilná s SQL – ale Yesql to nezaujíma. Nikdy nebudete strácať čas hľadaním funkcií so syntaxou ekvivalentnou SQL. Už sa nikdy nemusíte vracať k funkcii (raw-sql "some('funky'::SYNTAX)")).
  • Lepšia podpora editorov. Váš editor už má vynikajúcu podporu SQL. Uložením SQL ako SQL ho môžete jednoducho použiť.
  • Tímová kompatibilita. Vaši DBA môžu čítať a zapisovať SQL, ktorý používate vo svojom projekte Clojure.
  • Jednoduchšie ladenie výkonu. Potrebujete zostaviť plán pre problematický dopyt? Toto nie je problém, keď je váš dotaz bežný SQL.
  • Opätovné použitie dopytov. Presuňte tie isté súbory SQL do iných projektov, pretože je to len starý dobrý SQL – stačí ho zdieľať.

Nápad je to podľa mňa veľmi cool a zároveň veľmi jednoduchý, vďaka čomu si projekt veľa získal nasledovníkov v rôznych jazykoch. A potom sa pokúsime aplikovať podobnú filozofiu oddelenia SQL kódu od všetkého ostatného ďaleko za ORM.

IDE a DB manažéri

Začnime jednoduchou každodennou úlohou. Často musíme hľadať nejaké objekty v databáze, napríklad nájsť tabuľku v schéme a študovať jej štruktúru (ktoré stĺpce, kľúče, indexy, obmedzenia atď. sú použité). A od akéhokoľvek grafického IDE alebo malého DB-managera v prvom rade čakáme práve na tieto schopnosti. Aby to bolo rýchle a nemuselo sa čakať pol hodiny, kým sa vykreslí okno s potrebnými informáciami (najmä pri pomalom pripojení na vzdialenú databázu), a zároveň, aby prijaté informácie boli čerstvé a relevantné a nevyžiadaná pošta. Navyše, čím je databáza zložitejšia a väčšia a čím väčší je ich počet, tým je to ťažšie.

Ale väčšinou hodím myš ďaleko a len napíšem kód. Povedzme, že chcete vedieť, ktoré tabuľky (a s akými vlastnosťami) sú obsiahnuté v schéme „HR“. Vo väčšine DBMS je možné požadovaný výsledok dosiahnuť pomocou takého jednoduchého dotazu z information_schema:

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

Od databázy k databáze sa obsah takýchto vyhľadávacích tabuliek líši v závislosti od možností každého DBMS. A napríklad pre MySQL z rovnakého adresára môžete získať parametre tabuľky špecifické pre tento DBMS:

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

Oracle nepozná information_schema, ale vie Metadáta Oraclea nie sú žiadne veľké problémy:

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

ClickHouse nie je výnimkou:

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

Niečo podobné sa dá urobiť v Cassandre (ktorá má namiesto tabuliek a klávesových priestorov namiesto schém columnfamilies):

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

Pre väčšinu ostatných databáz môžete tiež prísť s podobnými dotazmi (dokonca aj Mongo špeciálny systém zberu, ktorý obsahuje informácie o všetkých kolekciách v systéme).

Samozrejme, týmto spôsobom môžete získať informácie nielen o tabuľkách, ale vo všeobecnosti o akomkoľvek objekte. Z času na čas láskaví ľudia zdieľajú takýto kód pre rôzne databázy, ako napríklad v sérii článkov habra „Funkcie pre dokumentovanie PostgreSQL databáz“ (ayb, Ben, telocvičňa). Mať v hlave celú tú horu dotazov a neustále ich písať je samozrejme „také“ potešenie, takže v mojom obľúbenom IDE / editore mám predpripravenú sadu úryvkov na často používané dotazy a ostáva už len zadajte názvy objektov do šablóny.

Vďaka tomu je tento spôsob navigácie a vyhľadávania objektov oveľa flexibilnejší, šetrí veľa času, umožňuje získať presne tie informácie a vo forme, v akej ich práve potrebujete (ako je napríklad popísané v príspevku „Export údajov z databázy v akomkoľvek formáte: čo dokážu IDE na platforme IntelliJ“).

Operácie s predmetmi

Potom, čo sme našli a preštudovali potrebné predmety, je čas urobiť s nimi niečo užitočné. Prirodzene aj bez toho, aby ste zložili prsty z klávesnice.

Nie je žiadnym tajomstvom, že jednoduché odstránenie tabuľky bude vyzerať rovnako v takmer všetkých databázach:

drop table hr.persons

Ale s vytvorením tabuľky je to už zaujímavejšie. Takmer každý DBMS (vrátane mnohých NoSQL) dokáže „vytvoriť tabuľku“ v tej či onej forme a jej hlavná časť sa bude dokonca len málo líšiť (názov, zoznam stĺpcov, typy údajov), ale ostatné detaily sa môžu dramaticky líšiť a závisia od interného zariadenia. a schopnosti konkrétneho DBMS. Môj obľúbený príklad je, že v dokumentácii Oracle je len jeden „holý“ BNF pre syntax „vytvoriť tabuľku“ zaberajú 31 strán. Iné DBMS majú skromnejšie možnosti, ale každý z nich má tiež veľa zaujímavých a jedinečných funkcií na vytváranie tabuliek (postgres, mysql, šváb, cassandra). Je nepravdepodobné, že niektorý grafický „čarodejník“ z nasledujúceho IDE (najmä univerzálneho) bude schopný plne pokryť všetky tieto schopnosti a ak áno, tak to nebude pohľad pre slabé povahy. Zároveň správne a včas napísané vyhlásenie vytvoriť tabuľku vám umožní ich všetky jednoducho používať, spraví ukladanie a prístup k vašim údajom spoľahlivé, optimálne a čo najpohodlnejšie.

Mnohé DBMS majú tiež svoje vlastné špecifické typy objektov, ktoré nie sú dostupné v iných DBMS. Okrem toho môžeme vykonávať operácie nielen na databázových objektoch, ale aj na samotnom DBMS, napríklad „zabiť“ proces, uvoľniť časť pamäte, povoliť sledovanie, prepnúť do režimu „iba na čítanie“ a oveľa viac.

A teraz poďme trochu kresliť

Jednou z najbežnejších úloh je zostaviť diagram s databázovými objektmi, vidieť objekty a vzťahy medzi nimi v krásnom obrázku. Dokáže to takmer každé grafické IDE, samostatné obslužné programy „príkazového riadku“, špecializované grafické nástroje a modelári. Ktoré vám niečo vykreslia „ako najlepšie vedia“ a tento proces môžete mierne ovplyvniť len pomocou niekoľkých parametrov v konfiguračnom súbore alebo checkboxov v rozhraní.

Ale tento problém sa dá vyriešiť oveľa jednoduchším, flexibilnejším a elegantnejším spôsobom a samozrejme pomocou kódu. Na zostavenie diagramov akejkoľvek zložitosti máme niekoľko špecializovaných značkovacích jazykov naraz (DOT, GraphML atď.) a pre nich - celý rad aplikácií (GraphViz, PlantUML, Mermaid), ktoré dokážu prečítať takéto pokyny a vizualizovať ich v rôznych formátov. No už vieme, ako získať informácie o objektoch a vzťahoch medzi nimi.

Uveďme si malý príklad, ako by to mohlo vyzerať s použitím PlantUML a demo databáza pre PostgreSQL (vľavo je SQL dotaz, ktorý vygeneruje požadovanú inštrukciu pre PlantUML a vpravo je výsledok):

Skúsenosti „Databáza ako Сode“.

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'

A ak sa trochu pokúsite, tak na základe Šablóna ER pre PlantUML môžete získať niečo veľmi podobné skutočnému ER diagramu:

SQL dotaz je trochu komplikovanejší

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

Skúsenosti „Databáza ako Сode“.

Ak sa pozriete pozorne, pod kapotou mnohé vizualizačné nástroje tiež používajú podobné dopyty. Je pravda, že tieto požiadavky sú zvyčajne hlboké „napevno“ zapojené do kódu samotnej aplikácie a ťažko pochopiteľnénehovoriac o ich úprave.

Metriky a monitorovanie

Prejdime k tradične ťažkej téme – monitorovaniu výkonu databázy. Spomínam si na malý skutočný príbeh, ktorý mi povedal „jeden z mojich priateľov“. Na ďalšom projekte žil istý mocný DBA a máloktorý z vývojárov ho osobne poznal a skutočne mu niekedy videl do očí (napriek tomu, že podľa povestí pracoval niekde v neďalekej budove). V hodine „X“, keď sa produkčný systém veľkého maloobchodníka opäť začal „necítiť“, v tichosti poslal screenshoty grafov z Oracle Enterprise Manager, na ktorých pre „jasnosť“ starostlivo zvýraznil kritické miesta červenou značkou. (toto, mierne povedané, veľmi nepomohlo). A táto „fotokartička“ musela byť ošetrená. Zároveň nikto nemal prístup k vzácnemu (v oboch významoch slova) Enterprise Manager. systém je zložitý a drahý, zrazu "vývojári na niečo narazia a všetko rozbijú." Preto vývojári „empiricky“ našli miesto a príčinu bŕzd a vydali záplatu. Ak ten strašný list od DBA v blízkej dobe opäť neprišiel, tak si všetci vydýchli a vrátili sa k svojim aktuálnym úlohám (až do nového Listu).

Proces monitorovania však môže vyzerať zábavnejšie a priateľskejšie, a čo je najdôležitejšie, prístupný a transparentný pre každého. Aspoň jeho základná časť, ako doplnok k hlavným monitorovacím systémom (ktoré sú určite užitočné a v mnohých prípadoch nenahraditeľné). Akýkoľvek DBMS je voľne a úplne zadarmo pripravený zdieľať informácie o svojom aktuálnom stave a výkone. V tej istej "krvavej" Oracle DB je možné získať takmer akékoľvek informácie o výkone zo systémových zobrazení, od procesov a relácií až po stav vyrovnávacej pamäte (napr. Skripty DBA, časť "Monitorovanie"). Postgresql má tiež veľa systémových zobrazení sledovanie prevádzky databázy, najmä také nepostrádateľné v každodennom živote každého DBA, ako je pg_stat_activity, pg_stat_database, pg_stat_bgwriter. V MySQL je na to určená dokonca samostatná schéma. výkonnostná_schéma. A B Mongo vstavaný profilovač agreguje údaje o výkone do systémovej kolekcie systémový.profil.

Takže vyzbrojení nejakým zberačom metrík (Telegraf, Metricbeat, Collectd), ktorý dokáže vykonávať vlastné SQL dotazy, úložiskom týchto metrík (InfluxDB, Elasticsearch, Timescaledb) a vizualizérom (Grafana, Kibana), môžete získať pomerne jednoduchý a flexibilný monitorovací systém, ktorý bude úzko integrovaný s ostatnými celosystémovými metrikami (získanými napr. z aplikačného servera, z OS atď.). Ako napríklad v pgwatch2, ktorý používa balík InfluxDB + Grafana a sadu dotazov na systémové zobrazenia, ktoré môžu byť pridať vlastné požiadavky.

Celkom

A to je len približný zoznam toho, čo sa dá s našou databázou robiť pomocou bežného SQL kódu. Som si istý, že nájdete oveľa viac aplikácií, napíšte do komentárov. A o tom, ako (a hlavne prečo) toto všetko zautomatizovať a zaradiť do vášho CI / CD pipeline, si povieme nabudúce.

Zdroj: hab.com

Pridať komentár