SQL, mi lehetne egyszerűbb? Mindannyian írhatunk egy egyszerű kérést – gépelünk válasszuk, sorolja fel a szükséges oszlopokat, majd ból ből, tábla neve, néhány feltétel ahol és ez minden – a hasznos adatok a zsebünkben vannak, és (majdnem) függetlenül attól, hogy melyik DBMS van akkoriban (vagy esetleg
És kezdjük rögtön onnan
Objektum-relációs leképezés
Az ORM támogatói hagyományosan nagyra értékelik a gyorsaságot és a könnyű fejlesztést, a DBMS-től való függetlenséget és a tiszta kódot. Sokunk számára az adatbázissal (és gyakran magával az adatbázissal) való munka kódja
általában valahogy így néz ki...
@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;
}
...
A modell okos megjegyzésekkel van kirakva, és valahol a színfalak mögött egy vitéz ORM generál és hajt végre néhány SQL kódot. A fejlesztők egyébként igyekeznek minden tőlük telhetőt elszigetelni magukat adatbázisuktól kilométeres absztrakciókkal, ami azt jelzi,
A barikádok másik oldalán a tisztán „kézzel készített” SQL hívei megjegyzik, hogy további rétegek és absztrakciók nélkül képesek minden levet kipréselni a DBMS-ből. Ennek eredményeként megjelennek az „adatközpontú” projektek, ahol speciálisan képzett embereket vonnak be az adatbázisba (ők is „alapisták”, ők is „alapisták”, ők is „basdenerek” stb.), illetve a fejlesztők. csak a kész nézeteket és tárolt eljárásokat kell „lehúzni”, anélkül, hogy belemennénk a részletekbe.
Mi lenne, ha mindkét világból a legjobbat kapnánk? Hogyan történik ez egy csodálatos eszközzel, életigenlő névvel
A Clojure egy klassz nyelv a DSL-ek létrehozásához, de az SQL maga egy klassz DSL, és nincs szükségünk másikra. Az S-kifejezések nagyszerűek, de nem adnak hozzá semmi újat. Ennek eredményeként zárójeleket kapunk a zárójelek kedvéért. Nem ért egyet? Ezután várja meg a pillanatot, amikor az adatbázis feletti absztrakció elkezd kiszivárogni, és harcolni kezd a funkcióval (nyers-sql)
Szóval mit tegyek? Hagyjuk az SQL-t normál SQL-ként – kérésenként egy fájl:
-- name: users-by-country
select *
from users
where country_code = :country_code
... majd olvassa el ezt a fájlt, és alakítsa át normál Clojure-függvénnyel:
(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" ...} ...)
Az "SQL önmagában, Clojure önmagában" elv betartásával a következőket kapja:
- Nincs szintaktikai meglepetés. Az Ön adatbázisa (mint bármely más) nem 100%-ban kompatibilis az SQL-szabvánnyal – de ez a Yesql esetében nem számít. Soha nem vesztegeti az idejét az SQL-vel egyenértékű szintaxisú függvények keresésével. Soha nem kell visszatérnie egy funkcióhoz (raw-sql "some('funky'::SYNTAX)")).
- A legjobb szerkesztő támogatás. Az Ön szerkesztője már kiváló SQL-támogatással rendelkezik. Ha az SQL-t SQL-ként menti, egyszerűen használhatja.
- Csapatkompatibilitás. A DBA-k képesek olvasni és írni a Clojure projektben használt SQL-t.
- Könnyebb teljesítményhangolás. Tervet kell készítenie egy problémás lekérdezéshez? Ez nem jelent problémát, ha a lekérdezés normál SQL.
- Lekérdezések újrafelhasználása. Húzza át ugyanazokat az SQL-fájlokat más projektekbe, mert ez csak egy régi SQL – csak ossza meg.
Véleményem szerint az ötlet nagyon klassz és egyben nagyon egyszerű, aminek köszönhetően a projekt rengeteget nyert
IDE és DB menedzserek
Kezdjük egy egyszerű mindennapi feladattal. Gyakran meg kell keresnünk néhány objektumot az adatbázisban, például meg kell találnunk egy táblát a sémában, és tanulmányoznunk kell a szerkezetét (milyen oszlopokat, kulcsokat, indexeket, megszorításokat stb. használunk). És minden grafikus IDE-től vagy egy kis DB-menedzsertől mindenekelőtt pontosan ezeket a képességeket várjuk el. Hogy gyors legyen, és ne kelljen fél órát várni, amíg kirajzolódik egy ablak a szükséges információkkal (főleg távoli adatbázishoz való lassú kapcsolat esetén), ugyanakkor a kapott információ friss és releváns, és nem gyorsítótárazott szemét. Sőt, minél összetettebb és nagyobb az adatbázis, és minél több van belőlük, annál nehezebb ezt megtenni.
De általában eldobom az egeret és csak kódot írok. Tegyük fel, hogy meg kell találnia, hogy a "HR" séma mely táblákat (és milyen tulajdonságokkal) tartalmazza. A legtöbb DBMS-ben a kívánt eredményt az information_schema egyszerű lekérdezésével érhetjük el:
select table_name
, ...
from information_schema.tables
where schema = 'HR'
Az ilyen referenciatáblázatok tartalma adatbázisonként az egyes DBMS-ek képességeitől függően változik. És például a MySQL-hez ugyanabból a referenciakönyvből szerezheti be a DBMS-re jellemző táblázatparamétereket:
select table_name
, storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
, row_format -- Формат строки ("Fixed", "Dynamic" etc)
, ...
from information_schema.tables
where schema = 'HR'
Az Oracle nem ismeri az information_schema-t, de igen
select table_name
, pct_free -- Минимум свободного места в блоке данных (%)
, pct_used -- Минимум используемого места в блоке данных (%)
, last_analyzed -- Дата последнего сбора статистики
, ...
from all_tables
where owner = 'HR'
A ClickHouse sem kivétel:
select name
, engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
Valami hasonlót megtehet a Cassandra (amelyben táblák helyett oszlopcsaládok, sémák helyett kulcsterek vannak):
select columnfamily_name
, compaction_strategy_class -- Стратегия сборки мусора
, gc_grace_seconds -- Время жизни мусора
, ...
from system.schema_columnfamilies
where keyspace_name = 'HR'
A legtöbb más adatbázis esetében is előállhat hasonló lekérdezések (még a Mongo is
Természetesen így nem csak a táblákról, hanem általában bármilyen objektumról szerezhet információkat. A kedves emberek időről időre megosztanak ilyen kódokat különböző adatbázisokhoz, mint például a „PostgreSQL adatbázisok dokumentálásának függvényei” című habra cikksorozatban (
Ennek eredményeként a navigáció és az objektumok keresésének ez a módszere sokkal rugalmasabb, sok időt takarít meg, és lehetővé teszi, hogy pontosan az információkat abban a formában kapja meg, amilyenben most szükséges (ahogy például a bejegyzésben le van írva
Műveletek tárgyakkal
Miután megtaláltuk és áttanulmányoztuk a szükséges tárgyakat, ideje valami hasznosat tenni velük. Természetesen anélkül, hogy levenné az ujjait a billentyűzetről.
Nem titok, hogy egy táblázat egyszerű törlése szinte minden adatbázisban ugyanúgy fog kinézni:
drop table hr.persons
De a táblázat elkészítésével érdekesebbé válik. Szinte minden DBMS (beleértve a sok NoSQL-t is) képes ilyen vagy olyan formában "táblázatot létrehozni", és ennek nagy része kissé eltér (név, oszloplista, adattípusok), de más részletek drámaian eltérhetnek, és függhetnek a egy adott DBMS belső eszköze és képességei. A kedvenc példám az, hogy az Oracle dokumentációjában csak „csupasz” BNF-ek vannak a „tábla létrehozása” szintaxishoz.
Ezenkívül sok DBMS-nek van saját objektumtípusa, amelyek más DBMS-ekben nem állnak rendelkezésre. Sőt, nem csak az adatbázis-objektumokon, hanem magán a DBMS-en is végezhetünk műveleteket, például „megölhetünk” egy folyamatot, felszabadíthatunk némi memóriaterületet, engedélyezhetjük a nyomkövetést, átválthatunk „csak olvasható” módba, és még sok minden mást.
Most rajzoljunk egy kicsit
Az egyik leggyakoribb feladat az adatbázis-objektumokkal diagram összeállítása, és az objektumok és a köztük lévő kapcsolatok gyönyörű képben való megjelenítése. Szinte bármilyen grafikus IDE, különálló „parancssori” segédprogramok, speciális grafikus eszközök és modellezők képesek erre. Lerajzolnak neked valamit, „amennyire csak tudnak”, és ezt a folyamatot csak a konfigurációs fájl néhány paraméterével vagy a felületen található jelölőnégyzetekkel tudod kicsit befolyásolni.
De ez a probléma sokkal egyszerűbben, rugalmasabban és elegánsabban is megoldható, és persze kód segítségével. Bármilyen bonyolultságú diagramok készítéséhez számos speciális jelölőnyelvünk (DOT, GraphML stb.) áll rendelkezésünkre, és ezekhez az alkalmazások egész sora (GraphViz, PlantUML, Mermaid), amelyek képesek elolvasni az ilyen utasításokat és különféle formátumokban megjeleníteni azokat. . Nos, már tudjuk, hogyan szerezzünk információkat az objektumokról és a köztük lévő kapcsolatokról.
Íme egy kis példa arra, hogyan nézhet ki ez a PlantUML és 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'
És ha egy kicsit próbálkozol, akkor az alapján
Az SQL lekérdezés egy kicsit bonyolultabb
-- Шапка
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'
Ha alaposan megnézi, a motorháztető alatt sok vizualizációs eszköz is használ hasonló lekérdezéseket. Igaz, ezek a kérések általában mélyek
Mérések és monitorozás
Térjünk át egy hagyományosan összetett témára - az adatbázis-teljesítmény figyelésére. Emlékszem egy kis igaz történetre, amelyet „egyik barátom” mesélt nekem. Egy másik projektben élt egy bizonyos erős DBA, és a fejlesztők közül kevesen ismerték őt személyesen, vagy valaha is találkoztak vele (annak ellenére, hogy a pletykák szerint valahol a szomszédos épületben dolgozott). Az „X” órában, amikor egy nagy kereskedő podukciós rendszere ismét „rosszul” kezdett érezni magát, csendben elküldte az Oracle Enterprise Manager grafikonjainak képernyőképeit, amelyeken az „érthetőség” érdekében piros jelzővel gondosan kiemelte a kritikus helyeket ( ez enyhén szólva nem sokat segített). És e „fotókártya” alapján kellett kezelnem. Ugyanakkor senki sem férhetett hozzá a becses (a szó mindkét értelmében) Enterprise Managerhez, mert a rendszer bonyolult és drága, hirtelen „a fejlesztők megbotlanak valamiben, és mindent összetörnek”. Ezért a fejlesztők „empirikusan” megtalálták a fékek helyét és okát, és kiadtak egy foltot. Ha a közeljövőben nem érkezne meg újra a fenyegető levél a DBA-tól, akkor mindenki fellélegezne, és visszatérne jelenlegi feladataihoz (az új Levélig).
De a megfigyelési folyamat szórakoztatóbbnak és barátságosabbnak tűnhet, és ami a legfontosabb, mindenki számára elérhető és átlátható. Legalábbis az alapvető része, kiegészítve a főbb felügyeleti rendszerekkel (amelyek minden bizonnyal hasznosak és sok esetben pótolhatatlanok). Bármely DBMS szabadon és teljesen ingyenesen oszthat meg információkat aktuális állapotáról és teljesítményéről. Ugyanabban a „véres” Oracle DB-ben szinte minden teljesítményre vonatkozó információ beszerezhető a rendszernézetekből, a folyamatoktól és a munkamenetektől a puffer-gyorsítótár állapotáig (például
Így felszerelkezve valamilyen metrikagyűjtővel (Telegraf, Metricbeat, Collectd), amely képes egyedi sql-lekérdezéseket végrehajtani, ezen mérőszámok tárolójával (InfluxDB, Elasticsearch, Timescaledb) és egy vizualizálóval (Grafana, Kibana) meglehetősen egyszerűen kaphat valamint egy rugalmas megfigyelőrendszer, amely szorosan integrálva lesz más rendszerszintű mérőszámokkal (például az alkalmazáskiszolgálóról, az operációs rendszerről stb.). Mint például ez megtörténik a pgwatch2-ben, amely az InfluxDB + Grafana kombinációt és a rendszernézetekhez tartozó lekérdezéseket használja, amelyek szintén elérhetők.
Összességében
És ez csak egy hozzávetőleges lista arról, hogy mit lehet tenni adatbázisunkkal normál SQL kód használatával. Biztos vagyok benne, hogy még sok felhasználási lehetőséget találsz, írd meg a megjegyzésekben. És arról fogunk beszélni, hogyan (és legfőképpen miért) automatizálhatjuk mindezt, és legközelebb beépíthetjük a CI/CD-folyamatba.
Forrás: will.com