"Мэдээллийн баазыг код болгон ашиглах" туршлага

"Мэдээллийн баазыг код болгон ашиглах" туршлага

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-ийг баримтлагчид нэмэлт давхарга, хийсвэрлэлгүйгээр DBMS-ийн бүх шүүсийг шахаж авах чадварыг тэмдэглэж байна. Үүний үр дүнд мэдээллийн санд тусгайлан бэлтгэгдсэн хүмүүс (тэд "суурь судлаач", тэд бас "суурь судлаач", мөн "баазист" гэх мэт) болон хөгжүүлэгчид оролцдог "өгөгдөл төвтэй" төслүүд гарч ирдэг. Дэлгэрэнгүй мэдээлэл оруулахгүйгээр зөвхөн бэлэн харагдах байдал, хадгалагдсан процедурыг "татах" хэрэгтэй.

Хэрэв бид хоёр ертөнцийн хамгийн шилдэг нь байсан бол яах вэ? Энэ нь амьдралыг батлах нэртэй гайхамшигтай хэрэгсэлд хэрхэн хийгддэг 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'

Өгөгдлийн сангаас өгөгдлийн сан хүртэл ийм лавлах хүснэгтүүдийн агуулга нь DBMS бүрийн чадавхиас хамааран өөр өөр байдаг. Жишээлбэл, MySQL-ийн хувьд ижил лавлах номноос та энэ DBMS-д хамаарах хүснэгтийн параметрүүдийг авч болно.

select table_name
     , storage_engine -- Используемый "движок" ("MyISAM", "InnoDB" etc)
     , row_format     -- Формат строки ("Fixed", "Dynamic" etc)
     , ...
  from information_schema.tables
 where schema = 'HR'

Oracle мэдээллийн схемийг мэддэггүй, гэхдээ түүнд байдаг 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/редактор дээр байнга ашигладаг асуулгад зориулж урьдчилан бэлтгэсэн хэсэгчилсэн багц байгаа бөгөөд зөвхөн асуултуудыг бичих л үлдлээ. объектын нэрийг загварт оруулна.

Үүний үр дүнд объект хайх, хайх энэ арга нь илүү уян хатан, маш их цаг хэмнэж, шаардлагатай мэдээллийг яг одоо шаардлагатай хэлбэрээр авах боломжийг олгодог (жишээлбэл, нийтлэлд тайлбарласан) "Өгөгдлийн сангаас өгөгдлийг ямар ч форматаар экспортлох: IntelliJ платформ дээр IDE-ууд юу хийж чадах вэ").

Объектуудтай хийх үйлдлүүд

Шаардлагатай объектуудыг олж, судалсны дараа тэдэнтэй ашигтай зүйл хийх цаг болжээ. Мэдээжийн хэрэг, гарнаас хуруугаа салгахгүйгээр.

Хүснэгтийг устгахад бараг бүх мэдээллийн санд адилхан харагдах нь нууц биш.

drop table hr.persons

Гэхдээ хүснэгтийг бий болгосноор энэ нь илүү сонирхолтой болно. Бараг ямар ч DBMS (олон NoSQL-г оруулаад) нэг хэлбэрээр "хүснэгт үүсгэх" боломжтой бөгөөд түүний үндсэн хэсэг нь бага зэрэг ялгаатай (нэр, баганын жагсаалт, өгөгдлийн төрөл) боловч бусад дэлгэрэнгүй мэдээлэл нь эрс ялгаатай байж болно. тодорхой DBMS-ийн дотоод төхөөрөмж болон боломжууд. Миний хамгийн дуртай жишээ бол Oracle баримт бичигт зөвхөн "хүснэгт үүсгэх" синтаксийн "нүцгэн" BNF-ууд байдаг. 31 хуудас эзэлнэ. Бусад DBMS нь илүү даруухан чадвартай боловч тэдгээр нь хүснэгт үүсгэх олон сонирхолтой, өвөрмөц онцлогтой байдаг.Шуудангийн материал, MySQL, жоом, cassandra). Өөр IDE-ийн ямар ч график "шидтэн" (ялангуяа бүх нийтийнх) эдгээр бүх чадварыг бүрэн хамарч чадах нь юу л бол, боломжтой байсан ч энэ нь сул дорой хүмүүст үзүүлэх үзэгдэл биш юм. Үүний зэрэгцээ зөв, цаг тухайд нь бичсэн мэдэгдэл хүснэгт үүсгэх Эдгээрийг бүгдийг нь хялбархан ашиглах, хадгалалт хийх, өгөгдөлд хандах хандалтыг найдвартай, оновчтой, аль болох тав тухтай болгох боломжийг танд олгоно.

Мөн олон DBMS нь бусад DBMS-д байдаггүй өөрийн гэсэн тусгай төрлийн объектуудтай байдаг. Түүнээс гадна бид зөвхөн өгөгдлийн сангийн объектууд дээр төдийгүй DBMS дээр үйлдлүүдийг гүйцэтгэх боломжтой, жишээлбэл, процессыг "алах", санах ойн зарим хэсгийг чөлөөлөх, мөрийг идэвхжүүлэх, "зөвхөн унших" горимд шилжих гэх мэт.

Одоо жаахан зурцгаая

Хамгийн түгээмэл даалгавруудын нэг бол өгөгдлийн сангийн объектуудтай диаграммыг барьж, тэдгээрийн хоорондох объект, холболтыг үзэсгэлэнтэй зургаар харах явдал юм. Бараг ямар ч график IDE, тусдаа "командын мөр" хэрэгсэл, тусгай график хэрэгсэл, загварчлагч үүнийг хийж чадна. Тэд танд зориулж ямар нэг зүйлийг "хамгийн сайнаараа" зурах бөгөөд та тохиргооны файл дахь цөөн хэдэн параметр эсвэл интерфэйс дэх тэмдэглэгээний тусламжтайгаар энэ үйл явцад бага зэрэг нөлөөлж чадна.

Гэхдээ энэ асуудлыг илүү энгийн, илүү уян хатан, гоёмсог, мэдээжийн хэрэг кодын тусламжтайгаар шийдэж болно. Ямар ч нарийн төвөгтэй диаграммыг бий болгохын тулд бид хэд хэдэн тусгай тэмдэглэгээний хэлүүд (DOT, GraphML гэх мэт) байдаг бөгөөд тэдгээрийн хувьд эдгээр зааврыг уншиж, янз бүрийн форматаар дүрслэх боломжтой бүхэл бүтэн програмууд (GraphViz, PlantUML, Mermaid) байдаг. . За, бид объектуудын тухай мэдээлэл, тэдгээрийн хоорондын холболтын талаар аль хэдийн мэддэг болсон.

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-ийн графикуудын дэлгэцийн агшинг чимээгүйхэн илгээж, эгзэгтэй газруудыг "ойлгомжтой" гэж улаан тэмдэглэгээгээр анхааралтай тодруулсан ( Энэ нь зөөлөн хэлэхэд тийм ч их тус болсонгүй). Мөн энэ "фото карт" дээр үндэслэн би эмчлэх шаардлагатай болсон. Үүний зэрэгцээ хэн ч үнэ цэнэтэй (энэ үгийн хоёр утгаараа) аж ахуйн нэгжийн менежерт хандах боломжгүй байсан, учир нь систем нь нарийн төвөгтэй бөгөөд үнэтэй тул "хөгжүүлэгчид ямар нэгэн зүйлд бүдэрч, бүх зүйлийг эвддэг". Тиймээс хөгжүүлэгчид тоормосны байршил, шалтгааныг "эмпирик байдлаар" олж, засвар хийсэн. Хэрэв DBA-аас айлган сүрдүүлсэн захидал ойрын хугацаанд дахин ирэхгүй бол хүн бүр тайвширч, одоо байгаа ажилдаа буцах болно (шинэ захидал хүртэл).

Гэхдээ хяналтын үйл явц нь илүү хөгжилтэй, найрсаг, хамгийн чухал нь хүн бүрт хүртээмжтэй, ил тод харагдаж болно. Наад зах нь түүний үндсэн хэсэг нь хяналтын үндсэн системд нэмэлт болгон (энэ нь мэдээж хэрэг ашигтай бөгөөд ихэнх тохиолдолд орлуулшгүй). Аливаа DBMS нь одоогийн байдал, гүйцэтгэлийн талаархи мэдээллийг чөлөөтэй, үнэ төлбөргүй хуваалцах боломжтой. Ижил "цуст" Oracle DB-д гүйцэтгэлийн талаарх бараг бүх мэдээллийг процесс, сессээс эхлээд буфер кэшийн төлөв хүртэл системийн харагдацаас авах боломжтой (жишээлбэл, DBA скриптүүд, хэсэг "Хяналт"). Postgresql-д бас олон тооны системийн үзэл бодол байдаг мэдээллийн сангийн мониторинг, ялангуяа аливаа DBA-ийн өдөр тутмын амьдралд зайлшгүй шаардлагатай зүйлүүд, тухайлбал pg_stat_activity, pg_stat_өгөгдлийн сан, pg_stat_bgwriter. MySQL-д үүнд зориулсан тусдаа схем байдаг. гүйцэтгэлийн_схем. A In Mongo-д суурилуулсан профайлчин гүйцэтгэлийн өгөгдлийг системийн цуглуулгад нэгтгэдэг систем.профайл.

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

Нийт

Энэ бол ердийн SQL кодыг ашиглан манай мэдээллийн санд юу хийж болох талаар зөвхөн ойролцоо жагсаалт юм. Та өөр олон хэрэглээг олж чадна гэдэгт итгэлтэй байна, сэтгэгдэл дээр бичээрэй. Энэ бүгдийг хэрхэн автоматжуулж (хамгийн чухал нь яагаад) дараагийн удаа CI/CD дамжуулах хоолойд оруулах талаар бид ярилцах болно.

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх