«Տվյալների բազան որպես ծածկագիր» փորձ

«Տվյալների բազան որպես ծածկագիր» փորձ

SQL, ինչ կարող է լինել ավելի պարզ: Մեզանից յուրաքանչյուրը կարող է գրել մի պարզ հարցում՝ մենք մուտքագրում ենք ընտրել, նշեք պահանջվող սյունակները, ապա - ից, աղյուսակի անվանումը, որոշ պայմաններ են որտեղ և դա բոլորն են. օգտակար տվյալները մեր գրպանում են, և (գրեթե) անկախ նրանից, թե որ DBMS-ն է գտնվում այդ պահին գլխարկի տակ (կամ գուցե ամենևին էլ DBMS չէ) Արդյունքում, գրեթե ցանկացած տվյալների աղբյուրի հետ աշխատելը (հարաբերական և ոչ այնքան) կարելի է դիտարկել սովորական կոդի տեսանկյունից (այն ամենով, ինչ դա ենթադրում է. տարբերակի վերահսկում, կոդի վերանայում, ստատիկ վերլուծություն, ավտոմատ փորձարկումներ և վերջ): Եվ դա վերաբերում է ոչ միայն բուն տվյալներին, սխեմաներին և միգրացիաներին, այլ ընդհանրապես պահպանման ողջ կյանքին: Այս հոդվածում մենք կխոսենք ամենօրյա խնդիրների և տվյալների բազաների հետ աշխատելու խնդիրների մասին՝ «շտեմարան որպես կոդ» ոսպնյակի ներքո։

Եվ եկեք սկսենք անմիջապես ՕՐՄ. «SQL vs ORM» տիպի առաջին մարտերը նկատվել են դեռևս նախա Պետրինե Ռուսաստան.

Օբյեկտ-հարաբերական քարտեզագրում

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 ատելություն».

Բարիկադների մյուս կողմում մաքուր «ձեռագործ» SQL-ի կողմնակիցները նշում են իրենց DBMS-ից ամբողջ հյութը քամելու հնարավորությունը՝ առանց լրացուցիչ շերտերի և աբստրակցիաների: Արդյունքում հայտնվում են «տվյալակենտրոն» նախագծեր, որտեղ տվյալների բազայում ներգրավված են հատուկ վերապատրաստված մարդիկ (նրանք նույնպես «հիմնարարներ են», նրանք նույնպես «բազիսիստներ» են, նրանք նույնպես «բազդեններ» են և այլն), և մշակողները. միայն պետք է «քաշել» պատրաստի դիտումները և պահված ընթացակարգերը՝ առանց մանրամասնելու։

Իսկ եթե մենք երկու աշխարհներից էլ լավագույնն ունենայինք: Ինչպես է դա արվում հիանալի գործիքի մեջ, որն ունի կյանքը հաստատող անունը Yesql. Ընդհանուր հայեցակարգից մի երկու տող կտամ իմ ազատ թարգմանության մեջ, և դուք կարող եք ավելի մանրամասն ծանոթանալ դրան. այստեղ.

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 է. պարզապես տարածեք այն:

Իմ կարծիքով, գաղափարը շատ թույն է և միևնույն ժամանակ շատ պարզ, ինչի շնորհիվ նախագիծը շատ է ձեռք բերել հետևորդներ տարբեր լեզուներով. Եվ մենք հաջորդիվ կփորձենք կիրառել SQL կոդը առանձնացնելու նմանատիպ փիլիսոփայություն ORM-ից հեռու մնացած ամեն ինչից:

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, բայց գիտի Oracle-ի մետատվյալներ, և մեծ խնդիրներ չեն առաջանում.

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 տվյալների շտեմարանների փաստաթղթավորման գործառույթներ» (Այբ, աղբարկղ, մարզասրահ) Իհարկե, հարցումների այս ամբողջ լեռն իմ գլխում պահելն ու դրանք անընդհատ մուտքագրելն այնքան հաճելի է, ուստի իմ սիրելի IDE/խմբագրիչում ես նախապես պատրաստված հատվածներ ունեմ հաճախ օգտագործվող հարցումների համար, և մնում է միայն մուտքագրել օբյեկտների անունները կաղապարի մեջ:

Արդյունքում, օբյեկտներ նավարկելու և որոնելու այս մեթոդը շատ ավելի ճկուն է, խնայում է շատ ժամանակ և թույլ է տալիս ստանալ ճշգրիտ տեղեկատվություն այն ձևով, որով դա այժմ անհրաժեշտ է (ինչպես, օրինակ, նկարագրված է գրառման մեջ. «Տվյալների արտահանում տվյալների բազայից ցանկացած ձևաչափով. ինչ կարող են անել IDE-ները IntelliJ հարթակում»).

Գործողություններ առարկաների հետ

Այն բանից հետո, երբ մենք գտել և ուսումնասիրել ենք անհրաժեշտ առարկաները, ժամանակն է դրանցով ինչ-որ օգտակար բան անել: Բնականաբար, նաև առանց մատները ստեղնաշարից հանելու։

Գաղտնիք չէ, որ պարզապես աղյուսակը ջնջելը նույն տեսքը կունենա գրեթե բոլոր տվյալների բազաներում.

drop table hr.persons

Բայց աղյուսակի ստեղծմամբ այն ավելի հետաքրքիր է դառնում։ Գրեթե ցանկացած DBMS (ներառյալ շատ NoSQL) կարող է «ստեղծել աղյուսակ» այս կամ այն ​​ձևով, և դրա հիմնական մասը նույնիսկ մի փոքր կտարբերվի (անունը, սյունակների ցանկը, տվյալների տեսակները), բայց այլ մանրամասներ կարող են կտրուկ տարբերվել և կախված լինել. ներքին սարքը և որոշակի DBMS-ի հնարավորությունները: Իմ սիրելի օրինակն այն է, որ Oracle-ի փաստաթղթերում կան միայն «մերկ» BNF-ներ «ստեղծել աղյուսակ» շարահյուսության համար: զբաղեցնում է 31 էջ. Այլ DBMS-ներն ունեն ավելի համեստ հնարավորություններ, սակայն դրանցից յուրաքանչյուրն ունի նաև աղյուսակներ ստեղծելու շատ հետաքրքիր և եզակի հնարավորություններ (postgres, MySQL, աքաղաղ, կասանդրա) Քիչ հավանական է, որ մեկ այլ IDE-ից (հատկապես ունիվերսալից) որևէ գրաֆիկական «վիզարդ» կարողանա ամբողջությամբ ծածկել այս բոլոր ունակությունները, և եթե նույնիսկ կարողանա, ապա դա տեսարան չի լինի թույլ սրտի համար: Միաժամանակ ճիշտ և ժամանակին գրավոր հայտարարություն աղյուսակ ստեղծել թույլ կտա հեշտությամբ օգտագործել դրանք բոլորը, դարձնել պահեստավորում և մուտք դեպի ձեր տվյալները հուսալի, օպտիմալ և հնարավորինս հարմարավետ:

Բացի այդ, շատ DBMS-ներ ունեն իրենց հատուկ տեսակի օբյեկտներ, որոնք հասանելի չեն այլ DBMS-ներում: Ավելին, մենք կարող ենք գործողություններ կատարել ոչ միայն տվյալների բազայի օբյեկտների, այլ նաև հենց DBMS-ի վրա, օրինակ՝ «սպանել» գործընթացը, ազատել որոշ հիշողության տարածք, միացնել հետագծումը, անցնել «միայն կարդալու» ռեժիմին և շատ ավելին:

Հիմա մի քիչ նկարենք

Ամենատարածված խնդիրներից մեկը տվյալների բազայի օբյեկտների հետ դիագրամ կառուցելն է և նրանց միջև եղած առարկաներն ու կապերը գեղեցիկ նկարում տեսնելը: Գրեթե ցանկացած գրաֆիկական IDE, առանձին «հրամանի տող» կոմունալ ծառայություններ, մասնագիտացված գրաֆիկական գործիքներ և մոդելավորողներ կարող են դա անել: Նրանք ձեզ համար ինչ-որ բան կնկարեն «ինչպես կարող են», և դուք կարող եք մի փոքր ազդել այս գործընթացի վրա միայն կազմաձևման ֆայլի մի քանի պարամետրերի կամ միջերեսի վանդակների օգնությամբ:

Բայց այս խնդիրը կարելի է լուծել շատ ավելի պարզ, ավելի ճկուն ու էլեգանտ, և իհարկե կոդի օգնությամբ։ Ցանկացած բարդության դիագրամներ ստեղծելու համար մենք ունենք մի քանի մասնագիտացված նշագրման լեզուներ (DOT, GraphML և այլն), և նրանց համար հավելվածների մի ամբողջ ցրվածություն (GraphViz, PlantUML, Mermaid), որոնք կարող են կարդալ նման հրահանգներ և պատկերացնել դրանք տարբեր ձևաչափերով: . Դե, մենք արդեն գիտենք, թե ինչպես կարելի է տեղեկատվություն ստանալ օբյեկտների և նրանց միջև կապերի մասին:

Ահա մի փոքրիկ օրինակ, թե ինչ կարող է նման լինել՝ օգտագործելով PlantUML և Դեմո տվյալների բազա PostgreSQL-ի համար (ձախ կողմում կա SQL հարցում, որը կստեղծի 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'

Եվ եթե մի փոքր փորձեք, ապա հիման վրա ER ձևանմուշ PlantUML-ի համար դուք կարող եք ստանալ մի բան, որը շատ նման է իրական ER դիագրամին.

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'

«Տվյալների բազան որպես ծածկագիր» փորձ

Եթե ​​ուշադիր նայեք, ապա կափարիչի տակ շատ վիզուալիզացիոն գործիքներ նույնպես օգտագործում են նմանատիպ հարցումներ: Ճիշտ է, այդ խնդրանքները սովորաբար խորն են «hardwired» է հավելվածի կոդը մեջ և դժվար է հասկանալ, էլ չեմ խոսում դրանց փոփոխության մասին։

Չափումներ և մոնիտորինգ

Անցնենք ավանդաբար բարդ թեմային՝ տվյալների բազայի կատարողականի մոնիտորինգ: Ես հիշում եմ մի փոքրիկ իրական պատմություն, որն ինձ պատմել է «իմ ընկերներից մեկը»: Մեկ այլ նախագծում ապրում էր որոշակի հզոր DBA, և մշակողներից քչերն էին նրան անձամբ ճանաչում կամ երբևէ տեսել էին նրան անձամբ (չնայած այն փաստին, որ, ըստ լուրերի, նա աշխատում էր ինչ-որ տեղ կողքի շենքում): «X» ժամին, երբ խոշոր մանրածախ վաճառողի արտադրության համակարգը նորից սկսեց «վատ զգալ», նա լուռ ուղարկեց գծապատկերների սքրինշոթներ Oracle Enterprise Manager-ից, որոնց վրա նա զգուշորեն ընդգծեց կարևոր վայրերը կարմիր նշիչով «հասկանալիության» համար ( սա, մեղմ ասած, այնքան էլ չօգնեց): Եվ այս «ֆոտոկարտի» հիման վրա ես ստիպված էի բուժել: Միևնույն ժամանակ, ոչ ոք մուտք չուներ թանկարժեք (բառի երկու իմաստով) Enterprise Manager-ին, քանի որ. համակարգը բարդ է և թանկ, հանկարծ «մշակողները սայթաքում են ինչ-որ բանի վրա և կոտրում են ամեն ինչ»: Հետևաբար, մշակողները «էմպիրիկորեն» գտան արգելակների գտնվելու վայրը և պատճառը և թողարկեցին կարկատ: Եթե ​​մոտ ապագայում կրկին չհասներ DBA-ի սպառնալից նամակը, ապա բոլորը հանգիստ շունչ կքաշեին ու կվերադառնային իրենց ընթացիկ գործին (մինչև նոր Նամակ):

Բայց մոնիտորինգի գործընթացը կարող է ավելի զվարճալի և ընկերական տեսք ունենալ, և ամենակարևորը՝ հասանելի և թափանցիկ բոլորի համար: Առնվազն դրա հիմնական մասը՝ որպես մոնիտորինգի հիմնական համակարգերի հավելում (որոնք իհարկե օգտակար են և շատ դեպքերում անփոխարինելի)։ Ցանկացած DBMS-ն ազատ և բացարձակապես անվճար է իր ընթացիկ վիճակի և կատարողականի մասին տեղեկությունների փոխանակման համար: Նույն «արյունոտ» Oracle DB-ում աշխատանքի մասին գրեթե ցանկացած տեղեկատվություն կարելի է ստանալ համակարգի դիտումներից՝ սկսած գործընթացներից և նիստերից մինչև բուֆերային քեշի վիճակը (օրինակ. DBA սցենարներ«Մոնիտորինգ» բաժինը): Postgresql-ն ունի նաև համակարգային դիտումների մի ամբողջ փունջ տվյալների բազայի մոնիտորինգ, մասնավորապես նրանք, որոնք անփոխարինելի են ցանկացած DBA-ի առօրյա կյանքում, ինչպես, օրինակ pg_stat_activity, pg_stat_database, pg_stat_bgwriter. MySQL-ն դրա համար նույնիսկ առանձին սխեմա ունի: կատարման_սխեմա. Ներկառուցված A In Mongo-ում պրոֆիլավորող միավորում է կատարողականի տվյալները համակարգի հավաքածուի մեջ system.profile.

Այսպիսով, զինված լինելով ինչ-որ չափումների հավաքիչով (Telegraf, Metricbeat, Collectd), որը կարող է կատարել հատուկ sql հարցումներ, այս չափումների պահեստավորում (InfluxDB, Elasticsearch, Timescaledb) և վիզուալիզատոր (Grafana, Kibana), դուք կարող եք բավականին հեշտ ստանալ: և մոնիտորինգի ճկուն համակարգ, որը սերտորեն ինտեգրված կլինի ամբողջ համակարգի այլ չափումների հետ (ստացված, օրինակ, հավելվածի սերվերից, ՕՀ-ից և այլն): Ինչպես, օրինակ, դա արվում է pgwatch2-ում, որն օգտագործում է InfluxDB + Grafana համակցությունը և հարցումների մի շարք համակարգի դիտումների համար, որոնց նույնպես կարելի է մուտք գործել: ավելացնել մաքսային հարցումներ.

Ընդհանուր

Եվ սա ընդամենը մոտավոր ցուցակ է, թե ինչ կարելի է անել մեր տվյալների բազայի հետ՝ օգտագործելով սովորական SQL կոդը: Համոզված եմ, որ դուք կարող եք գտնել ավելի շատ կիրառումներ, գրեք մեկնաբանություններում: Եվ մենք կխոսենք այն մասին, թե ինչպես (և ամենակարևորը ինչու) ավտոմատացնել այս ամենը և հաջորդ անգամ այն ​​ներառել ձեր CI/CD խողովակաշարում:

Source: www.habr.com

Добавить комментарий