SQL, ինչ կարող է լինել ավելի պարզ: Մեզանից յուրաքանչյուրը կարող է գրել մի պարզ հարցում՝ մենք մուտքագրում ենք ընտրել, նշեք պահանջվող սյունակները, ապա - ից, աղյուսակի անվանումը, որոշ պայմաններ են որտեղ և դա բոլորն են. օգտակար տվյալները մեր գրպանում են, և (գրեթե) անկախ նրանից, թե որ DBMS-ն է գտնվում այդ պահին գլխարկի տակ (կամ գուցե
Եվ եկեք սկսենք անմիջապես
Օբյեկտ-հարաբերական քարտեզագրում
ORM-ի կողմնակիցները ավանդաբար գնահատում են զարգացման արագությունն ու հեշտությունը, անկախությունը DBMS-ից և մաքուր կոդը: Մեզանից շատերի համար տվյալների բազայի հետ աշխատելու կոդը (և հաճախ հենց տվյալների բազան)
սովորաբար այսպիսի տեսք ունի...
@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;
}
...
Մոդելը կախված է խելացի անոտացիաներով, և ինչ-որ տեղ կուլիսների հետևում խիզախ ORM-ը ստեղծում և կատարում է տոննաներով որոշ SQL կոդ: Ի դեպ, մշակողները փորձում են առավելագույնը մեկուսացնել իրենց տվյալների բազայից կիլոմետրանոց աբստրակցիաներով, ինչը ցույց է տալիս որոշ
Բարիկադների մյուս կողմում մաքուր «ձեռագործ» SQL-ի կողմնակիցները նշում են իրենց DBMS-ից ամբողջ հյութը քամելու հնարավորությունը՝ առանց լրացուցիչ շերտերի և աբստրակցիաների: Արդյունքում հայտնվում են «տվյալակենտրոն» նախագծեր, որտեղ տվյալների բազայում ներգրավված են հատուկ վերապատրաստված մարդիկ (նրանք նույնպես «հիմնարարներ են», նրանք նույնպես «բազիսիստներ» են, նրանք նույնպես «բազդեններ» են և այլն), և մշակողները. միայն պետք է «քաշել» պատրաստի դիտումները և պահված ընթացակարգերը՝ առանց մանրամասնելու։
Իսկ եթե մենք երկու աշխարհներից էլ լավագույնն ունենայինք: Ինչպես է դա արվում հիանալի գործիքի մեջ, որն ունի կյանքը հաստատող անունը
Clojure-ը թույն լեզու է DSL-ներ ստեղծելու համար, բայց SQL-ն ինքնին հիանալի DSL է, և մեզ ուրիշի կարիք չկա: S-արտահայտությունները հիանալի են, բայց այստեղ ոչ մի նոր բան չեն ավելացնում: Արդյունքում մենք ստանում ենք փակագծեր հանուն փակագծերի։ Համաձայն չե՞ք։ Այնուհետև սպասեք այն պահին, երբ տվյալների բազայի աբստրակցիան կսկսի արտահոսել, և դուք կսկսեք պայքարել ֆունկցիայի հետ (հում-sql)
Այսպիսով, ինչ պետք է անեմ: Եկեք թողնենք SQL-ը որպես սովորական SQL՝ մեկ ֆայլ յուրաքանչյուր հարցում.
-- name: users-by-country
select *
from users
where country_code = :country_code
... և այնուհետև կարդացեք այս ֆայլը՝ այն վերածելով սովորական 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" ...} ...)
Հավատարիմ մնալով «SQL ինքնին, Clojure ինքնին» սկզբունքին, դուք ստանում եք.
- Չկան շարահյուսական անակնկալներ. Ձեր տվյալների բազան (ինչպես ցանկացած այլ) 100%-ով չի համապատասխանում SQL ստանդարտին, բայց Yesql-ի համար դա նշանակություն չունի: Դուք երբեք ժամանակ չեք վատնի SQL համարժեք շարահյուսությամբ ֆունկցիաներ փնտրելու համար: Դուք երբեք ստիպված չեք լինի վերադառնալ գործառույթ (raw-sql «որոշ ('funky'::SYNTAX)»)).
- Լավագույն խմբագրի աջակցություն: Ձեր խմբագիրն արդեն ունի գերազանց SQL աջակցություն: Պահպանելով SQL-ը որպես SQL, դուք կարող եք պարզապես օգտագործել այն:
- Թիմային համատեղելիություն. Ձեր DBA-ները կարող են կարդալ և գրել SQL-ը, որն օգտագործում եք ձեր Clojure նախագծում:
- Կատարման ավելի հեշտ կարգավորում: Պե՞տք է պլան կազմել խնդրահարույց հարցման համար: Սա խնդիր չէ, երբ ձեր հարցումը սովորական SQL է:
- Հարցումների կրկնակի օգտագործում: Քաշեք և գցեք այդ նույն SQL ֆայլերը այլ նախագծերի մեջ, քանի որ այն պարզապես հին SQL է. պարզապես տարածեք այն:
Իմ կարծիքով, գաղափարը շատ թույն է և միևնույն ժամանակ շատ պարզ, ինչի շնորհիվ նախագիծը շատ է ձեռք բերել
IDE & DB մենեջերներ
Սկսենք մի պարզ առօրյա առաջադրանքից. Հաճախ մենք ստիպված ենք լինում տվյալների բազայում փնտրել որոշ օբյեկտներ, օրինակ՝ սխեմայում գտնել աղյուսակ և ուսումնասիրել դրա կառուցվածքը (ինչ սյունակներ, ստեղներ, ինդեքսներ, սահմանափակումներ և այլն են օգտագործվում): Եվ ցանկացած գրաֆիկական IDE-ից կամ մի փոքր DB-մենեջերից, առաջին հերթին, մենք ակնկալում ենք հենց այս ունակությունները: Որպեսզի դա արագ լինի, և ստիպված չլինեք կես ժամ սպասել, մինչև գծվի անհրաժեշտ տեղեկություններով պատուհանը (հատկապես հեռավոր տվյալների բազայի հետ դանդաղ միացումով), և միևնույն ժամանակ ստացված տեղեկատվությունը թարմ և տեղին լինի, և ոչ քեշավորված աղբ: Ավելին, որքան բարդ և մեծ է տվյալների բազան և որքան մեծ է դրանց թիվը, այնքան ավելի դժվար է դա անել:
Բայց սովորաբար ես մկնիկը դեն եմ նետում ու ուղղակի կոդ եմ գրում։ Ենթադրենք, դուք պետք է պարզեք, թե որ աղյուսակները (և որ հատկություններով են) պարունակվում «HR» սխեմայում: DBMS-ների մեծ մասում ցանկալի արդյունքի կարելի է հասնել Information_schema-ից այս պարզ հարցման միջոցով.
select table_name
, ...
from information_schema.tables
where schema = 'HR'
Տվյալների բազայից տվյալների բազա, նման տեղեկատու աղյուսակների բովանդակությունը տարբերվում է՝ կախված յուրաքանչյուր DBMS-ի հնարավորություններից: Եվ, օրինակ, MySQL-ի համար, նույն տեղեկատու գրքից կարող եք ստանալ այս DBMS-ին հատուկ աղյուսակի պարամետրեր.
select table_name
, storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
, row_format -- Формат строки ("Fixed", "Dynamic" etc)
, ...
from information_schema.tables
where schema = 'HR'
Oracle-ը չգիտի information_schema, բայց գիտի
select table_name
, pct_free -- Минимум свободного места в блоке данных (%)
, pct_used -- Минимум используемого места в блоке данных (%)
, last_analyzed -- Дата последнего сбора статистики
, ...
from all_tables
where owner = 'HR'
ClickHouse-ը բացառություն չէ.
select name
, engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
, ...
from system.tables
where database = 'HR'
Նման բան կարելի է անել Կասանդրայում (որը աղյուսակների փոխարեն ունի սյունակային ընտանիքներ և սխեմաների փոխարեն՝ ստեղնային տարածքներ).
select columnfamily_name
, compaction_strategy_class -- Стратегия сборки мусора
, gc_grace_seconds -- Время жизни мусора
, ...
from system.schema_columnfamilies
where keyspace_name = 'HR'
Այլ տվյալների բազաների մեծ մասի համար կարող եք նաև նմանատիպ հարցումներ առաջացնել (նույնիսկ Մոնգոն ունի
Իհարկե, այս կերպ դուք կարող եք տեղեկատվություն ստանալ ոչ միայն աղյուսակների, այլ ընդհանրապես ցանկացած օբյեկտի մասին։ Ժամանակ առ ժամանակ բարի մարդիկ կիսվում են այնպիսի ծածկագրերով տարբեր տվյալների բազաների համար, ինչպես, օրինակ, հաբրա հոդվածների շարքում «PostgreSQL տվյալների շտեմարանների փաստաթղթավորման գործառույթներ» (
Արդյունքում, օբյեկտներ նավարկելու և որոնելու այս մեթոդը շատ ավելի ճկուն է, խնայում է շատ ժամանակ և թույլ է տալիս ստանալ ճշգրիտ տեղեկատվություն այն ձևով, որով դա այժմ անհրաժեշտ է (ինչպես, օրինակ, նկարագրված է գրառման մեջ.
Գործողություններ առարկաների հետ
Այն բանից հետո, երբ մենք գտել և ուսումնասիրել ենք անհրաժեշտ առարկաները, ժամանակն է դրանցով ինչ-որ օգտակար բան անել: Բնականաբար, նաև առանց մատները ստեղնաշարից հանելու։
Գաղտնիք չէ, որ պարզապես աղյուսակը ջնջելը նույն տեսքը կունենա գրեթե բոլոր տվյալների բազաներում.
drop table hr.persons
Բայց աղյուսակի ստեղծմամբ այն ավելի հետաքրքիր է դառնում։ Գրեթե ցանկացած DBMS (ներառյալ շատ NoSQL) կարող է «ստեղծել աղյուսակ» այս կամ այն ձևով, և դրա հիմնական մասը նույնիսկ մի փոքր կտարբերվի (անունը, սյունակների ցանկը, տվյալների տեսակները), բայց այլ մանրամասներ կարող են կտրուկ տարբերվել և կախված լինել. ներքին սարքը և որոշակի DBMS-ի հնարավորությունները: Իմ սիրելի օրինակն այն է, որ Oracle-ի փաստաթղթերում կան միայն «մերկ» BNF-ներ «ստեղծել աղյուսակ» շարահյուսության համար:
Բացի այդ, շատ DBMS-ներ ունեն իրենց հատուկ տեսակի օբյեկտներ, որոնք հասանելի չեն այլ DBMS-ներում: Ավելին, մենք կարող ենք գործողություններ կատարել ոչ միայն տվյալների բազայի օբյեկտների, այլ նաև հենց DBMS-ի վրա, օրինակ՝ «սպանել» գործընթացը, ազատել որոշ հիշողության տարածք, միացնել հետագծումը, անցնել «միայն կարդալու» ռեժիմին և շատ ավելին:
Հիմա մի քիչ նկարենք
Ամենատարածված խնդիրներից մեկը տվյալների բազայի օբյեկտների հետ դիագրամ կառուցելն է և նրանց միջև եղած առարկաներն ու կապերը գեղեցիկ նկարում տեսնելը: Գրեթե ցանկացած գրաֆիկական IDE, առանձին «հրամանի տող» կոմունալ ծառայություններ, մասնագիտացված գրաֆիկական գործիքներ և մոդելավորողներ կարող են դա անել: Նրանք ձեզ համար ինչ-որ բան կնկարեն «ինչպես կարող են», և դուք կարող եք մի փոքր ազդել այս գործընթացի վրա միայն կազմաձևման ֆայլի մի քանի պարամետրերի կամ միջերեսի վանդակների օգնությամբ:
Բայց այս խնդիրը կարելի է լուծել շատ ավելի պարզ, ավելի ճկուն ու էլեգանտ, և իհարկե կոդի օգնությամբ։ Ցանկացած բարդության դիագրամներ ստեղծելու համար մենք ունենք մի քանի մասնագիտացված նշագրման լեզուներ (DOT, GraphML և այլն), և նրանց համար հավելվածների մի ամբողջ ցրվածություն (GraphViz, PlantUML, Mermaid), որոնք կարող են կարդալ նման հրահանգներ և պատկերացնել դրանք տարբեր ձևաչափերով: . Դե, մենք արդեն գիտենք, թե ինչպես կարելի է տեղեկատվություն ստանալ օբյեկտների և նրանց միջև կապերի մասին:
Ահա մի փոքրիկ օրինակ, թե ինչ կարող է նման լինել՝ օգտագործելով PlantUML և
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'
Եվ եթե մի փոքր փորձեք, ապա հիման վրա
SQL հարցումը մի փոքր ավելի բարդ է
-- Шапка
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'
Եթե ուշադիր նայեք, ապա կափարիչի տակ շատ վիզուալիզացիոն գործիքներ նույնպես օգտագործում են նմանատիպ հարցումներ: Ճիշտ է, այդ խնդրանքները սովորաբար խորն են
Չափումներ և մոնիտորինգ
Անցնենք ավանդաբար բարդ թեմային՝ տվյալների բազայի կատարողականի մոնիտորինգ: Ես հիշում եմ մի փոքրիկ իրական պատմություն, որն ինձ պատմել է «իմ ընկերներից մեկը»: Մեկ այլ նախագծում ապրում էր որոշակի հզոր DBA, և մշակողներից քչերն էին նրան անձամբ ճանաչում կամ երբևէ տեսել էին նրան անձամբ (չնայած այն փաստին, որ, ըստ լուրերի, նա աշխատում էր ինչ-որ տեղ կողքի շենքում): «X» ժամին, երբ խոշոր մանրածախ վաճառողի արտադրության համակարգը նորից սկսեց «վատ զգալ», նա լուռ ուղարկեց գծապատկերների սքրինշոթներ Oracle Enterprise Manager-ից, որոնց վրա նա զգուշորեն ընդգծեց կարևոր վայրերը կարմիր նշիչով «հասկանալիության» համար ( սա, մեղմ ասած, այնքան էլ չօգնեց): Եվ այս «ֆոտոկարտի» հիման վրա ես ստիպված էի բուժել: Միևնույն ժամանակ, ոչ ոք մուտք չուներ թանկարժեք (բառի երկու իմաստով) Enterprise Manager-ին, քանի որ. համակարգը բարդ է և թանկ, հանկարծ «մշակողները սայթաքում են ինչ-որ բանի վրա և կոտրում են ամեն ինչ»: Հետևաբար, մշակողները «էմպիրիկորեն» գտան արգելակների գտնվելու վայրը և պատճառը և թողարկեցին կարկատ: Եթե մոտ ապագայում կրկին չհասներ DBA-ի սպառնալից նամակը, ապա բոլորը հանգիստ շունչ կքաշեին ու կվերադառնային իրենց ընթացիկ գործին (մինչև նոր Նամակ):
Բայց մոնիտորինգի գործընթացը կարող է ավելի զվարճալի և ընկերական տեսք ունենալ, և ամենակարևորը՝ հասանելի և թափանցիկ բոլորի համար: Առնվազն դրա հիմնական մասը՝ որպես մոնիտորինգի հիմնական համակարգերի հավելում (որոնք իհարկե օգտակար են և շատ դեպքերում անփոխարինելի)։ Ցանկացած DBMS-ն ազատ և բացարձակապես անվճար է իր ընթացիկ վիճակի և կատարողականի մասին տեղեկությունների փոխանակման համար: Նույն «արյունոտ» Oracle DB-ում աշխատանքի մասին գրեթե ցանկացած տեղեկատվություն կարելի է ստանալ համակարգի դիտումներից՝ սկսած գործընթացներից և նիստերից մինչև բուֆերային քեշի վիճակը (օրինակ.
Այսպիսով, զինված լինելով ինչ-որ չափումների հավաքիչով (Telegraf, Metricbeat, Collectd), որը կարող է կատարել հատուկ sql հարցումներ, այս չափումների պահեստավորում (InfluxDB, Elasticsearch, Timescaledb) և վիզուալիզատոր (Grafana, Kibana), դուք կարող եք բավականին հեշտ ստանալ: և մոնիտորինգի ճկուն համակարգ, որը սերտորեն ինտեգրված կլինի ամբողջ համակարգի այլ չափումների հետ (ստացված, օրինակ, հավելվածի սերվերից, ՕՀ-ից և այլն): Ինչպես, օրինակ, դա արվում է pgwatch2-ում, որն օգտագործում է InfluxDB + Grafana համակցությունը և հարցումների մի շարք համակարգի դիտումների համար, որոնց նույնպես կարելի է մուտք գործել:
Ընդհանուր
Եվ սա ընդամենը մոտավոր ցուցակ է, թե ինչ կարելի է անել մեր տվյալների բազայի հետ՝ օգտագործելով սովորական SQL կոդը: Համոզված եմ, որ դուք կարող եք գտնել ավելի շատ կիրառումներ, գրեք մեկնաբանություններում: Եվ մենք կխոսենք այն մասին, թե ինչպես (և ամենակարևորը ինչու) ավտոմատացնել այս ամենը և հաջորդ անգամ այն ներառել ձեր CI/CD խողովակաշարում:
Source: www.habr.com