SQL, šta može biti jednostavnije? Svako od nas može napisati jednostavan zahtjev - kucamo izabrati, zatim navedite potrebne kolone od, ime tabele, neki uslovi u gdje i to je sve - korisni podaci su u našem džepu, i (skoro) bez obzira na to koji DBMS je u tom trenutku ispod haube (ili možda
I počnimo odmah od
Objektno-relacijsko mapiranje
Pristalice ORM-a tradicionalno cijene brzinu i lakoću razvoja, nezavisnost od DBMS-a i čist kod. Za mnoge od nas, kod za rad sa bazom podataka (a često i samom bazom podataka)
obično izgleda otprilike ovako...
@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 okačen pametnim napomenama, a negdje iza kulisa hrabri ORM generiše i izvršava tone nekog SQL koda. Inače, programeri se svim silama trude da se izoluju od svoje baze podataka kilometrima apstrakcija, što ukazuje na neke
S druge strane barikada, pristalice čistog “ručnog” SQL-a primjećuju sposobnost da istisnu sav sok iz svog DBMS-a bez dodatnih slojeva i apstrakcija. Kao rezultat toga, pojavljuju se „data-centric“ projekti, gdje su posebno obučeni ljudi uključeni u bazu podataka (oni su i „bazičari“, oni su i „bazičari“, oni su također „basdeneri“ itd.), a programeri samo treba da „povuku“ gotove poglede i uskladištene procedure, bez ulaženja u detalje.
Šta ako imamo najbolje od oba svijeta? Kako se to radi u prekrasnom alatu sa životno potvrđujućim imenom
Clojure je kul jezik za kreiranje DSL-ova, ali sam SQL je kul DSL i ne treba nam drugi. S-izrazi su odlični, ali ovdje ne dodaju ništa novo. Kao rezultat, dobijamo zagrade radi zagrada. Ne slažete se? Zatim sačekajte trenutak kada apstrakcija nad bazom podataka počne da curi i počnete da se borite sa funkcijom (raw-sql)
Pa šta da radim? Ostavimo SQL kao običan SQL - jedan fajl po zahtjevu:
-- name: users-by-country
select *
from users
where country_code = :country_code
... a zatim pročitajte ovaj fajl, pretvarajući ga u redovnu Clojure funkciju:
(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" ...} ...)
Pridržavajući se principa "SQL sam, Clojure sam" dobijate:
- Nema sintaktičkih iznenađenja. Vaša baza podataka (kao i svaka druga) nije 100% usklađena sa SQL standardom - ali to nije važno za Yesql. Nikada nećete gubiti vrijeme tražeći funkcije sa SQL ekvivalentnom sintaksom. Nikada se nećete morati vraćati na funkciju (raw-sql "neki('funky'::SINTAX)")).
- Najbolja podrška za urednike. Vaš uređivač već ima odličnu SQL podršku. Ako sačuvate SQL kao SQL, možete ga jednostavno koristiti.
- Timska kompatibilnost. Vaši DBA mogu čitati i pisati SQL koji koristite u svom Clojure projektu.
- Lakše podešavanje performansi. Trebate napraviti plan za problematičan upit? Ovo nije problem kada je vaš upit običan SQL.
- Ponovno korištenje upita. Prevucite i ispustite te iste SQL datoteke u druge projekte jer je to običan stari SQL - samo ga podijelite.
Po mom mišljenju, ideja je vrlo cool i istovremeno vrlo jednostavna, zahvaljujući čemu je projekat dobio mnoge
IDE & DB menadžeri
Počnimo s jednostavnim svakodnevnim zadatkom. Često moramo tražiti neke objekte u bazi podataka, na primjer, pronaći tabelu u šemi i proučiti njenu strukturu (koji stupci, ključevi, indeksi, ograničenja itd. se koriste). I od bilo kog grafičkog IDE-a ili malog DB-managera, prije svega, očekujemo upravo ove sposobnosti. Tako da bude brzo i da ne morate čekati pola sata dok se ne iscrta prozor sa potrebnim informacijama (posebno kod sporog povezivanja na udaljenu bazu podataka), a da pritom primljene informacije budu svježe i relevantne, a ne keširano smeće. Štaviše, što je baza podataka složenija i veća i što ih je veći, to je teže to učiniti.
Ali obično bacim miša i samo napišem kod. Recimo da trebate saznati koje su tabele (i sa kojim svojstvima) sadržane u "HR" šemi. U većini DBMS-ova, željeni rezultat se može postići ovim jednostavnim upitom iz information_schema:
select table_name
, ...
from information_schema.tables
where schema = 'HR'
Od baze podataka do baze podataka, sadržaj takvih referentnih tabela varira ovisno o mogućnostima svakog DBMS-a. I, na primjer, za MySQL, iz istog priručnika možete dobiti parametre tablice specifične za ovaj DBMS:
select table_name
, storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
, row_format -- Формат строки ("Fixed", "Dynamic" etc)
, ...
from information_schema.tables
where schema = 'HR'
Oracle ne poznaje information_schema, ali ima
select table_name
, pct_free -- Минимум свободного места в блоке данных (%)
, pct_used -- Минимум используемого места в блоке данных (%)
, last_analyzed -- Дата последнего сбора статистики
, ...
from all_tables
where owner = 'HR'
ClickHouse nije izuzetak:
select name
, engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
Nešto slično se može učiniti u Cassandri (koja ima porodice stupaca umjesto tabela i ključeve umjesto shema):
select columnfamily_name
, compaction_strategy_class -- Стратегия сборки мусора
, gc_grace_seconds -- Время жизни мусора
, ...
from system.schema_columnfamilies
where keyspace_name = 'HR'
Za većinu drugih baza podataka, također možete smisliti slične upite (čak i Mongo ima
Naravno, na ovaj način možete dobiti informacije ne samo o tablicama, već o bilo kojem objektu općenito. S vremena na vrijeme ljubazni ljudi dijele takav kod za različite baze podataka, kao, na primjer, u seriji članaka o habri „Funkcije za dokumentiranje PostgreSQL baza podataka“ (
Kao rezultat toga, ova metoda navigacije i traženja objekata je mnogo fleksibilnija, štedi puno vremena i omogućava vam da dobijete upravo one informacije u obliku u kojem su sada potrebne (kao što je, na primjer, opisano u postu
Operacije sa objektima
Nakon što smo pronašli i proučili potrebne predmete, vrijeme je da s njima učinimo nešto korisno. Naravno, takođe bez skidanja prstiju sa tastature.
Nije tajna da će jednostavno brisanje tabele izgledati isto u skoro svim bazama podataka:
drop table hr.persons
Ali sa stvaranjem stola postaje zanimljivije. Gotovo svaki DBMS (uključujući mnoge NoSQL) može „kreirati tabelu“ u ovom ili onom obliku, a njen glavni dio će se čak i neznatno razlikovati (naziv, lista kolona, tipovi podataka), ali ostali detalji mogu se drastično razlikovati i ovisiti o interni uređaj i mogućnosti određenog DBMS-a. Moj omiljeni primjer je da u Oracle dokumentaciji postoje samo "goli" BNF-ovi za sintaksu "kreiraj tablicu"
Također, mnogi DBMS-ovi imaju svoje specifične tipove objekata koji nisu dostupni u drugim DBMS-ovima. Štoviše, možemo izvoditi operacije ne samo na objektima baze podataka, već i na samom DBMS-u, na primjer, „ubiti“ proces, osloboditi dio memorije, omogućiti praćenje, prebaciti se na način rada „samo za čitanje“ i još mnogo toga.
Sada da crtamo malo
Jedan od najčešćih zadataka je da napravite dijagram sa objektima baze podataka i vidite objekte i veze između njih u prelepoj slici. Gotovo svaki grafički IDE, odvojeni uslužni programi "komandne linije", specijalizovani grafički alati i modeli mogu to učiniti. Oni će vam nešto nacrtati „najbolje što mogu“, a na ovaj proces možete malo uticati samo uz pomoć nekoliko parametara u konfiguracionoj datoteci ili checkbox-a u interfejsu.
Ali ovaj problem se može riješiti mnogo jednostavnije, fleksibilnije i elegantnije, naravno uz pomoć koda. Za kreiranje dijagrama bilo koje složenosti imamo nekoliko specijaliziranih jezika za označavanje (DOT, GraphML itd.), a za njih čitav niz aplikacija (GraphViz, PlantUML, Mermaid) koje mogu čitati takve upute i vizualizirati ih u raznim formatima . Pa, već znamo kako doći do informacija o objektima i vezama između njih.
Evo malog primjera kako bi ovo moglo izgledati, koristeći PlantUML i
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 ako pokušate malo, onda na osnovu
SQL upit je malo složeniji
-- Шапка
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'
Ako pažljivo pogledate, ispod haube mnogi alati za vizualizaciju također koriste slične upite. Istina, ovi zahtjevi su obično duboki
metrika i praćenje
Pređimo na tradicionalno složenu temu - praćenje performansi baze podataka. Sjećam se male istinite priče koju mi je ispričao “jedan od mojih prijatelja”. Na drugom projektu živio je određeni moćni DBA, i malo ko od programera ga je lično poznavao, ili ga je ikada lično vidio (uprkos činjenici da je, prema glasinama, radio negdje u susjednoj zgradi). U satu „X“, kada je proizvodni sistem velikog trgovca ponovo počeo da se „oseća loše“, u tišini je poslao screenshotove grafikona iz Oracle Enterprise Manager-a, na kojima je pažljivo označio kritična mesta crvenim markerom za „razumljivost“ ( ovo, blago rečeno, nije puno pomoglo). I na osnovu ove "foto kartice" morao sam da tretiram. Istovremeno, niko nije imao pristup dragocenom (u oba smisla te reči) Enterprise Manageru, jer sistem je složen i skup, odjednom "programeri naiđu na nešto i sve pokvare." Stoga su programeri "empirijski" pronašli lokaciju i uzrok kočnica i pustili zakrpu. Da prijeteće pismo iz DBA ne stigne ponovo u bliskoj budućnosti, onda bi svi odahnuli i vratili se svojim trenutnim zadacima (do novog Pisma).
Ali proces praćenja može izgledati zabavnije i prijateljskije, i što je najvažnije, pristupačnije i transparentnije za sve. Barem njegov osnovni dio, kao dodatak glavnim sistemima praćenja (koji su svakako korisni i u mnogim slučajevima nezamjenjivi). Svaki DBMS može slobodno i apsolutno besplatno dijeliti informacije o svom trenutnom stanju i performansama. U istom „krvavom“ Oracle DB-u, gotovo sve informacije o performansama mogu se dobiti iz sistemskih pogleda, u rasponu od procesa i sesija do stanja keša bafera (na primjer,
Dakle, naoružani nekom vrstom sakupljača metrika (Telegraf, Metricbeat, Collectd) koji može izvoditi prilagođene sql upite, skladištenje ovih metrika (InfluxDB, Elasticsearch, Timescaledb) i vizualizator (Grafana, Kibana), možete dobiti prilično jednostavan i fleksibilan sistem praćenja koji će biti blisko integrisan sa drugim sistemskim metrikama (dobijenim, na primer, sa servera aplikacija, iz OS-a, itd.). Kao što se, na primjer, radi u pgwatch2, koji koristi kombinaciju InfluxDB + Grafana i skup upita za sistemske poglede, kojima se također može pristupiti
Ukupno
A ovo je samo približna lista onoga što se može učiniti s našom bazom podataka koristeći uobičajeni SQL kod. Sigurna sam da možete naći još mnogo primjena, pišite u komentarima. A mi ćemo razgovarati o tome kako (i najvažnije zašto) sve ovo automatizirati i uključiti u svoj CI/CD kanal sljedeći put.
izvor: www.habr.com