«Дерекқор код ретінде» тәжірибесі

«Дерекқор код ретінде» тәжірибесі

SQL, не қарапайым болуы мүмкін? Әрқайсымыз қарапайым сұранысты жаза аламыз - тереміз таңдау, содан кейін қажетті бағандарды тізімдеңіз -дан, кесте атауы, кейбір шарттар қайда және бұл бәрі - пайдалы деректер біздің қалтамызда және (дерлік) сол уақытта қандай ДҚБЖ (немесе мүмкін) қақпақтың астында екеніне қарамастан мүлде ДҚБЖ емес). Нәтижесінде, кез келген дерлік деректер көзімен жұмыс істеуді (қатысты және олай емес) қарапайым код тұрғысынан қарастыруға болады (оның барлығын білдіреді - нұсқаны басқару, кодты қарап шығу, статикалық талдау, автотесттер және барлығы). Және бұл деректердің өзіне, схемалар мен тасымалдауларға ғана емес, жалпы жадтың бүкіл қызмет ету мерзіміне де қатысты. Бұл мақалада біз күнделікті міндеттер мен әртүрлі деректер базаларымен жұмыс істеу проблемалары туралы «деректер базасы код ретінде» объективінде сөйлесетін боламыз.

Ал дәл осыдан бастайық ORM. «SQL және ORM» түріндегі алғашқы шайқастар қайтадан байқалды петринге дейінгі орыс.

Объектілік қатынасты бейнелеу

ORM қолдаушылары дәстүр бойынша жылдамдық пен өңдеудің қарапайымдылығын, ДҚБЖ тәуелсіздігін және таза кодты бағалайды. Біздің көпшілігіміз үшін дерекқормен жұмыс істеу коды (және көбінесе дерекқордың өзі)

әдетте бұл сияқты көрінеді ...

@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 "кейбір('funky'::SYNTAX)")).
  • Ең жақсы редакторды қолдау. Редакторыңызда SQL-ті тамаша қолдау бар. SQL-ді SQL ретінде сақтау арқылы оны жай ғана пайдалануға болады.
  • Топтық үйлесімділік. Сіздің DBA бағдарламаларыңыз Clojure жобаңызда пайдаланатын SQL тілін оқи және жаза алады.
  • Оңай өнімділікті реттеу. Проблемалық сұрауға жоспар құру керек пе? Сұрауыңыз кәдімгі SQL болса, бұл мәселе емес.
  • Сұрауларды қайта пайдалану. Сол SQL файлдарын басқа жобаларға сүйреп апарыңыз, себебі бұл қарапайым ескі SQL - жай ғана ортақ пайдаланыңыз.

Менің ойымша, идея өте керемет және сонымен бірге өте қарапайым, соның арқасында жоба көптеген нәрселерге ие болды ізбасарлары әртүрлі тілдерде. Әрі қарай біз SQL кодын ORM-дан тыс қалған барлық нәрселерден бөлудің ұқсас философиясын қолдануға тырысамыз.

IDE және DB менеджерлері

Қарапайым күнделікті тапсырмадан бастайық. Көбінесе мәліметтер қорындағы кейбір объектілерді іздеуге тура келеді, мысалы, схемадан кестені тауып, оның құрылымын (қандай бағандар, кілттер, индекстер, шектеулер және т.б. пайдаланылады) зерттеуге тура келеді. Кез келген графикалық IDE немесе кішкене DB-менеджерден, ең алдымен, біз дәл осы қабілеттерді күтеміз. Бұл жылдам болуы және қажетті ақпараты бар терезе (әсіресе қашықтағы дерекқорға баяу қосылым) салынғанша жарты сағат күтудің қажеті жоқ, сонымен бірге алынған ақпарат жаңа және өзекті, және кэштелген қоқыс емес. Оның үстіне, деректер базасы неғұрлым күрделі және үлкен болса және олардың саны неғұрлым көп болса, соғұрлым оны жасау қиынырақ.

Бірақ әдетте мен тінтуірді лақтырып жіберемін және жай ғана код жазамын. «HR» схемасында қандай кестелер (және қандай қасиеттері бар) бар екенін анықтау керек делік. Көптеген ДҚБЖ-да қажетті нәтижеге information_schema ішінен осы қарапайым сұрау арқылы қол жеткізуге болады:

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

Дерекқордан дерекқорға дейін мұндай анықтамалық кестелердің мазмұны әрбір ДҚБЖ мүмкіндіктеріне байланысты өзгереді. Және, мысалы, MySQL үшін сол анықтамалықтан осы ДҚБЖ-ға тән кесте параметрлерін алуға болады:

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'

Басқа дерекқорлардың көпшілігі үшін сіз ұқсас сұрауларды таба аласыз (тіпті Mongo-да да бар арнайы жүйе жинағы, ол жүйедегі барлық жинақтар туралы ақпаратты қамтиды).

Әрине, осылайша кестелер туралы ғана емес, жалпы кез келген объект туралы ақпарат алуға болады. Кейде мейірімді адамдар әртүрлі дерекқорлар үшін осындай кодты бөліседі, мысалы, «PostgreSQL дерекқорларын құжаттау функциялары» хабра мақалалар сериясында (Айб, мен, Спорт залы). Әрине, менің басымда осы сұраулар тауын сақтау және оларды үнемі теру - бұл үлкен ғанибет, сондықтан менің сүйікті IDE/редакторымда жиі қолданылатын сұраулар үшін алдын ала дайындалған үзінділер жинағы бар және қалғаны бар. нысан атауларын үлгіге енгізіңіз.

Нәтижесінде, объектілерді шарлау мен іздеудің бұл әдісі әлдеқайда икемді, көп уақытты үнемдейді және дәл қазір қажет пішінде ақпаратты алуға мүмкіндік береді (мысалы, постта сипатталғандай) «Дерекқордан деректерді кез келген форматта экспорттау: IntelliJ платформасында IDE не істей алады»).

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

Біз қажетті нысандарды тауып, зерттегеннен кейін олармен пайдалы нәрсе жасау уақыты келді. Әрине, саусақтарыңызды пернетақтадан шығармай-ақ.

Кестені жай ғана жою барлық дерлік дерекқорларда бірдей болатыны жасырын емес:

drop table hr.persons

Бірақ кестені құрумен ол қызықты болады. Кез келген дерлік ДҚБЖ (соның ішінде көптеген NoSQL) сол немесе басқа пішінде «кестені құра» алады және оның негізгі бөлігі тіпті аздап ерекшеленеді (атауы, бағандар тізімі, деректер түрлері), бірақ басқа мәліметтер күрт ерекшеленуі мүмкін және олардың түріне байланысты болады. ішкі құрылғы және нақты ДҚБЖ мүмкіндіктері. Менің сүйікті мысалым, Oracle құжаттамасында «кесте жасау» синтаксисі үшін тек «жалаңаш» BNF бар. 31 бетті алады. Басқа ДҚБЖ неғұрлым қарапайым мүмкіндіктерге ие, бірақ олардың әрқайсысында кестелерді құруға арналған көптеген қызықты және бірегей мүмкіндіктер бар (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-ден графиктердің скриншоттарын жіберді, онда ол «түсініктілік» үшін қызыл маркермен маңызды жерлерді мұқият белгіледі ( бұл, жұмсартып айтқанда, көп көмектеспеді). Осы «фотокартаның» негізінде мен емдеуге тура келді. Сонымен қатар, ешкімнің бағалы (сөздің екі мағынасында да) кәсіпорын менеджеріне қолы жетпеді, өйткені жүйе күрделі және қымбат, кенеттен «әзірлеушілер бірдеңеге сүрініп, бәрін бұзады». Сондықтан әзірлеушілер «эмпирикалық» тежегіштердің орны мен себебін тауып, патч шығарды. Егер DBA-дан қорқытатын хат жақын арада қайта келмесе, онда бәрі жеңіл дем алып, ағымдағы міндеттеріне оралар еді (жаңа Хатқа дейін).

Бірақ мониторинг процесі әлдеқайда қызықты және мейірімді, ең бастысы, барлығына қолжетімді және ашық көрінуі мүмкін. Кем дегенде оның негізгі бөлігі, негізгі мониторинг жүйелеріне қосымша ретінде (олар, әрине, пайдалы және көп жағдайда алмастырылмайтын). Кез келген ДҚБЖ оның ағымдағы күйі мен өнімділігі туралы ақпаратты бөлісу үшін еркін және мүлдем тегін. Дәл сол «қанды» 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) қарулансаңыз, өте оңай алуға болады. және басқа жалпы жүйелік көрсеткіштермен тығыз біріктірілетін икемді бақылау жүйесі (мысалы, қолданба серверінен, ОЖ-дан және т.б. алынған). Мысалы, бұл InfluxDB + Grafana тіркесімін және жүйе көріністеріне сұраулар жинағын пайдаланатын pgwatch2 бағдарламасында орындалады, оған да кіруге болады. реттелетін сұрауларды қосыңыз.

Барлығы

Бұл қарапайым SQL кодын пайдаланып біздің дерекқорымызбен не істеуге болатынының шамамен тізімі ғана. Тағы да көптеген қолдануларды таба алатыныңызға сенімдімін, түсініктемелерде жазыңыз. Мұның бәрін қалай (және ең бастысы неліктен) автоматтандыру және оны келесі жолы CI/CD құбырына қосу туралы сөйлесеміз.

Ақпарат көзі: www.habr.com

пікір қалдыру