"Код катары маалымат базасы" тажрыйбасы

"Код катары маалымат базасы" тажрыйбасы

SQL, эмне жөнөкөй болушу мүмкүн? Ар бирибиз жөнөкөй өтүнүч жаза алабыз - биз теребиз тандоо, талап кылынган тилкелерди тизмектеп, анан чейин, таблица аты, кээ бир шарттар кайда жана баары - пайдалуу маалыматтар биздин чөнтөгүбүздө жана (дээрлик) ошол учурда кайсы DBMS капчыктын астында экендигине карабастан (же мүмкүн болушу мүмкүн) такыр DBMS эмес). Натыйжада, дээрлик бардык маалымат булагы менен иштөө (байланыштуу жана андай эмес) кадимки коддун көз карашы менен каралышы мүмкүн (анын бардыгы менен - ​​версияны башкаруу, кодду карап чыгуу, статикалык талдоо, автотесттер жана ушуну менен бирге). Жана бул маалыматтардын өзүнө, схемаларга жана миграцияга гана эмес, жалпысынан сактоонун бүткүл өмүрүнө тиешелүү. Бул макалада биз күнүмдүк милдеттери жана ар кандай маалымат базалары менен иштөө көйгөйлөрү жөнүндө сөз болот "Код катары маалымат базасы" объективинде.

Жана андан баштайлы ORM. "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дин жактоочулары кошумча катмарларсыз жана абстракцияларсыз СББнын бардык ширесин сыгып алуу мүмкүнчүлүгүн белгилешет. Натыйжада «дата-борбордук» долбоорлор пайда болуп, анда маалымат базасына атайын даярдалган адамдар тартылат (алар дагы «базистер», алар дагы «базистер», алар дагы «базачылар» ж.б.), иштеп чыгуучулар Болгону майда-чүйдөсүнө чейин кирбестен, даяр көрүнүштөрдү жана сакталган процедураларды "тартуу" керек.

Эгер биз эки дүйнөнүн эң жакшысына ээ болсокчы? Бул жашоону тастыктаган аты менен сонун куралда кантип жасалат Yesql. Мен эркин котормомдо жалпы түшүнүктөн бир-эки сап берем, аны менен кененирээк тааныша аласыздар бул жерде.

Clojure - бул DSLлерди түзүү үчүн сонун тил, бирок SQL өзү сонун DSL жана бизге башкасынын кереги жок. S-экспрессиялары сонун, бирок алар бул жерде жаңы эч нерсе кошпойт. Натыйжада, биз кашаа үчүн кашааларды алабыз. макул эмессизби? Андан кийин маалымат базасы боюнча абстракция агып баштаган учурду күтүңүз жана сиз функция менен күрөшө баштайсыз (raw-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 өзүнөн өзү" принцибин кармануу менен, сиз төмөнкүлөрдү аласыз:

  • Синтаксистик сюрприз жок. Сиздин маалымат базаңыз (башкалары сыяктуу) SQL стандартына 100% туура келбейт - бирок Yesql үчүн бул маанилүү эмес. SQL эквиваленттүү синтаксиси бар функцияларды издөөгө эч качан убакыт коротпойсуз. Сиз эч качан функцияга кайтууга туура келбейт (raw-sql "some('funky'::SYNTAX)")).
  • Эң мыкты редактор колдоо. Сиздин редакторуңуз мурунтан эле мыкты SQL колдоосуна ээ. SQLди SQL катары сактоо менен сиз аны жөн гана колдоно аласыз.
  • Команда шайкештиги. Сиздин DBA'ларыңыз Clojure долбооруңузда колдонгон SQLди окуп жана жаза алышат.
  • Оңой аткарууну жөндөө. Көйгөйлүү суроо үчүн план түзүү керекпи? Сиздин сурооңуз кадимки SQL болгондо, бул көйгөй эмес.
  • Сурамдарды кайра колдонуу. Ошол эле SQL файлдарын башка долбоорлорго сүйрөп барып таштаңыз, анткени бул жөн эле эски SQL - жөн гана бөлүшүңүз.

Менин оюмча, идея абдан сонун жана ошол эле учурда абдан жөнөкөй, анын аркасында долбоор көптөгөн ээ болду жолдоочулары ар кандай тилдерде. Жана биз SQL кодун ORMден тышкаркы бардык нерселерден бөлүүнүн окшош философиясын колдонууга аракет кылабыз.

IDE жана DB менеджерлери

Жөнөкөй күнүмдүк тапшырмадан баштайлы. Көбүнчө маалымат базасынан кээ бир объекттерди издөөгө туура келет, мисалы, схемадан таблицаны таап, анын структурасын изилдөөгө туура келет (кандай мамычалар, ачкычтар, индекстер, чектөөлөр ж.б. колдонулат). Жана кандайдыр бир графикалык IDEден же кичинекей DB-менеджерден, биринчи кезекте, биз дал ушул жөндөмдөрдү күтөбүз. Бул тез жана керектүү маалыматы бар терезе тартылганга чейин жарым саат күтпөстөн (айрыкча алыскы маалымат базасына жай туташууда) жана ошол эле учурда алынган маалымат жаңы жана актуалдуу болушу үчүн, жана кэштелген таштанды эмес. Анын үстүнө, маалымат базасы канчалык татаал жана чоң болсо жана алардын саны канчалык көп болсо, муну жасоо ошончолук кыйын болот.

Бирок, адатта, мен чычканды ыргытып, жөн гана код жазам. "HR" схемасында кайсы таблицалар (жана кайсы касиеттери менен) камтылганын билишиңиз керек дейли. Көпчүлүк DBMS, каалаган натыйжага information_schema бул жөнөкөй суроо менен жетишүүгө болот:

select table_name
     , ...
  from information_schema.tables
 where schema = 'HR'

Берилиштер базасынан маалымат базасына чейин, мындай маалымдама таблицалардын мазмуну ар бир СББнын мүмкүнчүлүктөрүнө жараша өзгөрүп турат. Жана, мисалы, 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'

Көпчүлүк башка маалымат базалары үчүн сиз да ушундай суроолорду бере аласыз (ал тургай Mongo да бар атайын система чогултуу, ал тутумдагы бардык коллекциялар жөнүндө маалыматты камтыйт).

Албетте, ушундай жол менен таблицалар жөнүндө гана эмес, жалпысынан каалаган объекти жөнүндө маалымат ала аласыз. Мезгил-мезгили менен боорукер адамдар, мисалы, "PostgreSQL маалымат базасын документтештирүү үчүн функциялар" деген хабра макалаларынын сериясында, мисалы, ар кандай маалымат базалары үчүн ушундай кодду бөлүшүшөт (Айб, Ben, спорт зал). Албетте, менин башымда ушул суроонун тоосун сактап калуу жана аларды тынымсыз терүү абдан ырахат, андыктан менин сүйүктүү IDE/редакторумда менде көп колдонулган сурамдар үчүн алдын ала даярдалган үзүндүлөр бар жана калганы бар. объекттин аталыштарын шаблонго киргизиңиз.

Натыйжада, объекттерди навигациялоонун жана издөөнүн бул ыкмасы кыйла ийкемдүү, көп убакытты үнөмдөйт жана так маалыматты азыр керектүү формада алууга мүмкүндүк берет (мисалы, постто сүрөттөлгөн сыяктуу) "Маалымат базасынан каалаган форматта экспорттоо: IntelliJ платформасында IDE эмне кыла алат").

Объекттер менен операциялар

Биз керектүү объектилерди таап, изилдеп чыккандан кийин, алар менен пайдалуу бир нерсе жасоого убакыт келди. Албетте, манжаларыңызды клавиатурадан чыгарбастан.

Таблицаны жөн эле жок кылуу дээрлик бардык маалымат базаларында бирдей көрүнүшү эч кимге жашыруун эмес:

drop table hr.persons

Бирок үстөлдүн түзүлүшү менен ал кызыктуураак болот. Дээрлик бардык DBMS (анын ичинде көптөгөн NoSQL) тигил же бул формада "таблицаны түзө" алат жана анын негизги бөлүгү бир аз айырмаланат (аты, мамычалардын тизмеси, маалымат түрлөрү), бирок башка деталдар кескин түрдө айырмаланышы мүмкүн жана алардан көз каранды болот. ички түзүлүш жана белгилүү бир DBMS мүмкүнчүлүктөрү. Менин сүйүктүү мисалым, Oracle документтеринде "таблица түзүү" синтаксиси үчүн "жылаңач" BNF гана бар. 31 бетти ээлейт. Башка DBMS дагы жөнөкөй мүмкүнчүлүктөргө ээ, бирок алардын ар бири да таблицаларды түзүү үчүн көптөгөн кызыктуу жана уникалдуу өзгөчөлүктөргө ээ (postgres, MySQL, Таракан, Кассандра). Башка IDEден (айрыкча универсалдуу) кандайдыр бир графикалык "сыйкырчы" бул жөндөмдөрдүн бардыгын толук камтышы күмөн, ал тургай, алсырап тургандар үчүн спектакль боло албайт. Ошол эле учурда туура жана өз убагында жазылган арыз таблица түзүү алардын бардыгын оңой колдонууга, сактоого жана маалыматтарыңызга жетүү үчүн ишенимдүү, оптималдуу жана мүмкүн болушунча ыңгайлуу болууга мүмкүндүк берет.

Ошондой эле, көптөгөн МББдер башка СББларда жок объекттердин өзүнүн спецификалык түрлөрүнө ээ. Мындан тышкары, биз маалыматтар базасынын объектилерине гана эмес, ошондой эле МББнын өзүндө да операцияларды жасай алабыз, мисалы, процессти "өлтүрө алабыз", эстутумдун бир бөлүгүн бошотуп, трассаны иштете алабыз, "окуу үчүн гана" режимине которула алабыз жана башка көптөгөн нерселер.

Эми бир аз тарталы

Эң кеңири таралган милдеттердин бири - маалымат базасынын объектилери менен диаграмма куруу жана алардын ортосундагы объекттерди жана байланыштарды кооз сүрөттө көрүү. Дээрлик бардык графикалык IDE, жеке "буйрук сабы" утилиталары, адистештирилген графикалык инструменттер жана модельерлер муну жасай алышат. Алар сиз үчүн "мүмкүн болушунча" бир нерсени тартышат, бирок сиз бул процесске конфигурация файлындагы бир нече параметрлердин же интерфейстеги белги кутучаларынын жардамы менен гана таасир эте аласыз.

Бирок бул маселени бир топ жөнөкөй, ийкемдүү жана көрктүү чечсе болот, албетте, коддун жардамы менен. Ар кандай татаалдыктагы диаграммаларды түзүү үчүн бизде бир нече атайын белгилөө тилдери бар (DOT, GraphML ж. . Ооба, биз объекттер жана алардын ортосундагы байланыштар жөнүндө кантип маалымат алууну билебиз.

Бул PlantUML жана колдонуу менен, бул кандай болушу мүмкүн экенин кичинекей бир мисал PostgreSQL үчүн демо базасы (сол жакта PlantUML үчүн талап кылынган нускаманы түзө турган SQL суроосу, ал эми оң жакта натыйжа):

"Код катары маалымат базасы" тажрыйбасы

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'

Ал эми бир аз аракет болсо, анда негизделген PlantUML үчүн ER үлгүсү чыныгы 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'

"Код катары маалымат базасы" тажрыйбасы

Эгер жакшылап карасаңыз, капоттун астында көптөгөн визуалдаштыруу куралдары да ушундай суроону колдонушат. Ырас, бул өтүнүчтөр көбүнчө терең Колдонмонун кодуна "катуу жабдылган" жана түшүнүү кыйын, алардын эч кандай өзгөртүүлөрүн айтпай эле коёлу.

Метрика жана мониторинг

Келгиле, салттуу татаал темага өтөлү - маалымат базасынын иштешинин мониторинги. "Досторумдун бири" айтып берген кичинекей чыныгы окуя эсимде. Дагы бир долбоордо белгилүү бир күчтүү DBA жашаган жана аны иштеп чыгуучулардын бир нечеси аны жеке билген, же аны жеке көргөн эмес (имиштер боюнча, ал кийинки имаратта бир жерде иштегенине карабастан). "X" саатында ири сатуучунун поддукция системасы дагы бир жолу "жаман сезе" баштаганда, ал унчукпай Oracle Enterprise Manager графиктеринин скриншотторун жөнөттү, анда ал "түшүнүктүүлүк" үчүн кызыл маркер менен кылдаттык менен критикалык жерлерди бөлүп көрсөткөн ( бул, жумшак айтканда, анча деле жардам берген жок). Ал эми бул "фотокарта" негизинде мен дарылоо керек болчу. Ошол эле учурда, эч ким баалуу (сөздүн эки маанисинде) Enterprise Manager мүмкүнчүлүгүнө ээ болгон эмес, анткени система татаал жана кымбат, күтүлбөгөн жерден "иштеп чыгуучулар бир нерсеге чалынып, баарын бузушат". Ошондуктан, иштеп чыгуучулар "эмпирикалык" тормоздун ордун жана себебин таап, жамаачы чыгарышты. Эгерде ДБАнын коркунучтуу каты жакынкы аралыкта кайра келбесе, анда ар бир адам жеңил дем алып, учурдагы милдеттерине (жаңы Катка чейин) кайтып келмек.

Бирок мониторинг процесси кызыктуураак жана достук, эң негизгиси бардыгы үчүн жеткиликтүү жана ачык көрүнүшү мүмкүн. Негизги мониторинг системаларына кошумча катары, жок эле дегенде, анын негизги бөлүгү (алар, албетте, пайдалуу жана көп учурларда алмаштырылгыс). Ар кандай МББ анын учурдагы абалы жана иштеши жөнүндө маалымат менен бөлүшүү үчүн эркин жана таптакыр бекер. Ошол эле "кандуу" Oracle DBде, процесстер менен сеанстардан баштап буфердик кэштин абалына чейин системалык көрүнүштөрдөн дээрлик бардык маалыматтарды алууга болот (мисалы, DBA скрипттери, бөлүм "Мониторинг"). Postgresql ошондой эле тутумдук көрүнүштөрдүн бир тобуна ээ маалымат базасына мониторинг, атап айтканда, ар кандай DBAнын күнүмдүк жашоосунда алмаштырылгыс нерселер, мисалы pg_stat_activity, pg_stat_database, pg_stat_bgwriter. MySQL да бул үчүн өзүнчө схемасы бар. аткаруу_схемасы. A In Mongo орнотулган профилатор аткаруу маалыматтарын тутум жыйнагына бириктирет system.profile.

Ошентип, ыңгайлаштырылган sql сурамдарын аткара турган кандайдыр бир метрика жыйноочу (Telegraf, Metricbeat, Collectd), бул метрикалардын сактагычы (InfluxDB, Elasticsearch, Timescaledb) жана визуализатор (Grafana, Kibana) менен куралдансаңыз, сиз оңой эле ала аласыз. жана башка жалпы системалык көрсөткүчтөр менен тыгыз интеграцияланган ийкемдүү мониторинг системасы (мисалы, колдонмо серверинен, ОСтен ж.б. алынган). Мисалы, бул pgwatch2де жасалат, анда InfluxDB + Grafana айкалышы жана системанын көрүнүштөрү үчүн сурамдардын жыйындысы колдонулат, аларга да кирүүгө болот жеке суроо кошуу.

жалпы

Бул кадимки SQL кодун колдонуу менен биздин маалымат базасы менен эмне кылса болорун болжолдуу тизмеси гана. Дагы көп колдонууну таба аласыз деп ишенем, комментарийге жазыңыз. Мунун баарын кантип автоматташтыруу (жана эң негизгиси эмне үчүн) жана кийинки жолу CI/CD түтүкчөсүнө кошуу керектиги жөнүндө сүйлөшөбүз.

Source: www.habr.com

Комментарий кошуу