SQL, što može biti jednostavnije? Svatko od nas može napisati jednostavan zahtjev - tipkamo odabrati, zatim navedite potrebne stupce iz, naziv tablice, neki uvjeti u gdje i to je sve - korisni podaci su u našem džepu, i (skoro) bez obzira na to koji je DBMS u tom trenutku pod haubom (ili možda
I krenimo odmah od
Objektno-relacijsko preslikavanje
Pobornici ORM-a tradicionalno cijene brzinu i jednostavnost razvoja, neovisnost o DBMS-u i čisti kod. Za mnoge od nas kod za rad s bazom podataka (a često i sama baza podataka)
to obično izgleda 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 obložen pametnim komentarima, a negdje iza kulisa hrabri ORM generira i izvršava gomilu nekog SQL koda. Usput, programeri se svim silama trude izolirati se od svoje baze podataka kilometrima apstrakcija, što ukazuje na neke
S druge strane barikada, pristaše čistog "ručno izrađenog" SQL-a primjećuju sposobnost da iscijede 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 također “basicists”, oni su također “basicists”, oni su također “basdeneri” itd.), a programeri samo treba "izvući" gotove poglede i pohranjene procedure, bez ulaženja u detalje.
Što ako imamo najbolje od oba svijeta? Kako se to radi u prekrasnom alatu imena koje potvrđuje život
Clojure je cool jezik za stvaranje DSL-ova, ali SQL je sam po sebi cool DSL i ne treba nam još jedan. S-izrazi su super, ali ne dodaju ništa novo ovdje. Kao rezultat toga, dobivamo zagrade radi zagrada. Ne slažem se? Zatim pričekajte trenutak kada apstrakcija nad bazom podataka počne curiti i počnete se boriti s funkcijom (raw-sql)
Što bih trebao napraviti? Ostavimo SQL kao obični SQL - jedna datoteka po zahtjevu:
-- name: users-by-country
select *
from users
where country_code = :country_code
... a zatim pročitajte ovu datoteku, pretvarajući je u običnu 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 načela "SQL sam po sebi, Clojure sam po sebi" dobivate:
- Bez 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 vratiti na funkciju (raw-sql "some('funky'::SYNTAX)")).
- Najbolja podrška za urednike. Vaš uređivač već ima izvrsnu podršku za SQL. Ako spremite SQL kao SQL, možete ga jednostavno koristiti.
- Kompatibilnost tima. Vaši administratori baze podataka 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 regularni SQL.
- Ponovno korištenje upita. Povucite 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, au isto vrijeme vrlo jednostavna, zahvaljujući kojoj je projekt stekao mnoge
IDE & DB menadžeri
Počnimo s jednostavnim svakodnevnim zadatkom. Često moramo tražiti neke objekte u bazi podataka, na primjer, pronaći tablicu u shemi i proučiti njezinu strukturu (koji se stupci, ključevi, indeksi, ograničenja itd. koriste). A od bilo kojeg grafičkog IDE-a ili malog DB-managera, prije svega, očekujemo upravo ove mogućnosti. Kako bi bilo brzo i ne morate čekati pola sata dok vam se ne iscrta prozor s potrebnim informacijama (pogotovo kod spore veze s udaljenom bazom podataka), a istovremeno su primljene informacije svježe i relevantne, a ne predmemorirano smeće. Štoviše, što je baza podataka složenija i veća i što je njihov broj 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 tablice (i s kojim svojstvima) sadržane u "HR" shemi. U većini DBMS-ova, željeni rezultat može se postići ovim jednostavnim upitom iz information_schema:
select table_name
, ...
from information_schema.tables
where schema = 'HR'
Od baze do baze podataka, sadržaj takvih referentnih tablica varira ovisno o mogućnostima svakog DBMS-a. I, na primjer, za MySQL, iz iste referentne knjige 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 informacijsku shemu, ali je poznaje
select table_name
, pct_free -- Минимум свободного места в блоке данных (%)
, pct_used -- Минимум используемого места в блоке данных (%)
, last_analyzed -- Дата последнего сбора статистики
, ...
from all_tables
where owner = 'HR'
ClickHouse nije iznimka:
select name
, engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
Nešto slično može se učiniti u Cassandri (koja ima obitelji stupaca umjesto tablica i prostore ključeva 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 habra članaka “Funkcije za dokumentiranje PostgreSQL baza podataka” (
Kao rezultat toga, ova metoda navigacije i traženja objekata mnogo je fleksibilnija, štedi puno vremena i omogućuje vam da dobijete točno one informacije u obliku u kojem su sada potrebne (kao što je, na primjer, opisano u postu
Operacije s objektima
Nakon što smo pronašli i proučili potrebne predmete, vrijeme je da učinimo nešto korisno s njima. Naravno, također bez skidanja prstiju s tipkovnice.
Nije tajna da će jednostavno brisanje tablice izgledati isto u gotovo svim bazama podataka:
drop table hr.persons
Ali s izradom stola postaje zanimljivije. Gotovo svaki DBMS (uključujući mnoge NoSQL) može "stvoriti tablicu" u ovom ili onom obliku, a njen glavni dio će se čak malo razlikovati (naziv, popis stupaca, tipovi podataka), ali ostali detalji mogu se dramatično razlikovati i ovise o interni uređaj i mogućnosti konkretnog DBMS-a. Moj omiljeni primjer je da u Oracle dokumentaciji postoje samo "goli" BNF-ovi za sintaksu "stvori 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 neko područje memorije, omogućiti praćenje, prebaciti se u način rada "samo za čitanje" i još mnogo toga.
Sada malo crtajmo
Jedan od najčešćih zadataka je izgraditi dijagram s objektima baze podataka i vidjeti objekte i veze između njih na lijepoj slici. Gotovo svaki grafički IDE, zasebni uslužni programi "komandne linije", specijalizirani grafički alati i modeliri to mogu učiniti. Oni će vam nacrtati nešto “kako znaju”, a na taj proces možete malo utjecati samo uz pomoć nekoliko parametara u konfiguracijskoj datoteci ili potvrdnim okvirima u sučelju.
Ali ovaj se problem može riješiti puno jednostavnije, fleksibilnije i elegantnije, i naravno uz pomoć koda. Za izradu 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 različitim formatima . Pa, već znamo kako doći do informacija o objektima i vezama među njima.
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 malo pokušate, onda na temelju
SQL upit je malo kompliciraniji
-- Шапка
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 bolje pogledate, ispod haube mnogi alati za vizualizaciju također koriste slične upite. Istina, ti su zahtjevi obično duboki
Mjerni podaci i praćenje
Prijeđimo na tradicionalno složenu temu - praćenje performansi baze podataka. Sjećam se male istinite priče koju mi je ispričao "jedan moj prijatelj". Na drugom projektu živio je određeni moćni DBA, a malo ga je programera poznavalo osobno ili ga je ikada osobno vidjelo (unatoč činjenici da je, prema glasinama, radio negdje u susjednoj zgradi). U satu “X”, kada se proizvodni sustav velikog trgovca ponovno počeo “lošiti”, u tišini je poslao screenshotove grafova iz Oracle Enterprise Managera, na kojima je kritična mjesta pažljivo istaknuo crvenim markerom radi “razumljivosti” ( ovo, blago rečeno, nije puno pomoglo). I na temelju ove "foto karte" koju sam morao liječiti. Istovremeno, nitko nije imao pristup dragocjenom (u oba smisla riječi) Enterprise Manageru, jer sustav je složen i skup, odjednom se "programeri spotaknu o nešto i sve pokvare." Stoga su programeri "empirijski" pronašli mjesto i uzrok kočnica i izdali zakrpu. Da prijeteći dopis DBA opet ne stigne u dogledno vrijeme, onda bi svi odahnuli i vratili se sadašnjim poslovima (do novog Dopisa).
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 nadzornim sustavima (koji su svakako korisni iu mnogim slučajevima nezamjenjivi). Svaki DBMS može slobodno i apsolutno besplatno dijeliti informacije o svom trenutnom stanju i performansama. U istoj "krvavoj" Oracle DB, gotovo sve informacije o performansama mogu se dobiti iz prikaza sustava, u rasponu od procesa i sesija do stanja međuspremnika (na primjer,
Dakle, naoružani nekom vrstom sakupljača metrika (Telegraf, Metricbeat, Collectd) koji može izvoditi prilagođene sql upite, pohranom tih metrika (InfluxDB, Elasticsearch, Timescaledb) i vizualizatorom (Grafana, Kibana), možete dobiti prilično jednostavan i fleksibilan sustav praćenja koji će biti usko integriran s drugim metrikama cijelog sustava (dobivenim, na primjer, s aplikacijskog poslužitelja, iz OS-a itd.). Kao što je, na primjer, to učinjeno u pgwatch2, koji koristi kombinaciju InfluxDB + Grafana i skup upita za preglede sustava, kojima se također može pristupiti
Ukupno
A ovo je samo približan popis onoga što se može učiniti s našom bazom podataka korištenjem uobičajenog SQL koda. Siguran sam da možete pronaći još mnogo drugih upotreba, napišite u komentarima. Razgovarat ćemo o tome kako (i što je najvažnije zašto) sve ovo automatizirati i sljedeći put uključiti u svoj CI/CD kanal.
Izvor: www.habr.com