"Kod Olarak Veritabanı" Deneyimi

"Kod Olarak Veritabanı" Deneyimi

SQL, daha basit ne olabilir? Her birimiz basit bir istek yazabiliriz - biz yazarız seçmek, gerekli sütunları listeleyin ve ardından itibaren, tablo adı, bazı koşullar nerede ve hepsi bu - yararlı veriler cebimizde ve (neredeyse) o sırada hangi DBMS'nin kaputun altında olduğuna bakılmaksızın (veya belki de) kesinlikle bir DBMS değil). Sonuç olarak, hemen hemen her veri kaynağıyla (ilişkisel olsun ya da olmasın) çalışmak, sıradan kodun bakış açısından düşünülebilir (tüm ima ettiği şeylerle birlikte - sürüm kontrolü, kod incelemesi, statik analiz, otomatik testler ve hepsi bu). Ve bu yalnızca verilerin kendisi, şemalar ve geçişler için değil, genel olarak depolamanın tüm ömrü için de geçerlidir. Bu yazıda “kod olarak veritabanı” merceği altında çeşitli veritabanlarıyla çalışmanın günlük görevleri ve sorunları hakkında konuşacağız.

Ve hemen başlayalım yılan. "SQL vs ORM" türünün ilk savaşları XNUMX'lerde fark edildi Petrine Rus öncesi.

Nesne-ilişkisel haritalama

ORM destekçileri geleneksel olarak hıza ve geliştirme kolaylığına, DBMS'den bağımsızlığa ve temiz koda değer verir. Birçoğumuz için veritabanıyla (ve çoğunlukla veritabanının kendisiyle) çalışmanın kodu

genelde şöyle görünür...

@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;
    }
  ...

Model akıllı açıklamalarla süslenmiştir ve perde arkasında bir yerde güçlü bir ORM tonlarca SQL kodu üretip çalıştırır. Bu arada, geliştiriciler kilometrelerce soyutlamayla kendilerini veritabanlarından izole etmek için ellerinden geleni yapıyorlar; "SQL nefreti".

Barikatların diğer tarafında, saf "el yapımı" SQL taraftarları, ek katmanlar ve soyutlamalar olmadan DBMS'lerinin tüm suyunu sıkabilme yeteneğine dikkat çekiyor. Sonuç olarak, özel eğitimli kişilerin veritabanına dahil olduğu (bunlar aynı zamanda “temelciler”, aynı zamanda “temelciler”, aynı zamanda “bazdenschiki” vb.) ve geliştiricilerin dahil olduğu “veri merkezli” projeler ortaya çıkıyor. ayrıntılara girmeden yalnızca hazır görünümleri ve saklı prosedürleri "çekmeniz" gerekir.

Ya her iki dünyanın da en iyisine sahip olsaydık? Bu, yaşamı onaylayan bir isme sahip harika bir araçla nasıl yapılır? Yesql. Ücretsiz çevirimde genel konseptten birkaç satır vereceğim ve onu daha detaylı tanıyabilirsiniz. burada.

Clojure, DSL oluşturmak için harika bir dildir, ancak SQL'in kendisi de harika bir DSL'dir ve başka bir dile ihtiyacımız yok. S ifadeleri harika ama buraya yeni bir şey eklemiyorlar. Sonuç olarak, parantez uğruna parantez alıyoruz. Katılmıyorum? Daha sonra veritabanı üzerindeki soyutlamanın sızmaya başlayacağı ve fonksiyonla kavga etmeye başlayacağınız anı bekleyin. (ham-sql)

Peki ne yapmalıyım? SQL'i normal SQL olarak bırakalım - istek başına bir dosya:

-- name: users-by-country
select *
  from users
 where country_code = :country_code

... ve ardından bu dosyayı normal bir Clojure işlevine dönüştürerek okuyun:

(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'in kendisi, Clojure'un kendisi" ilkesine bağlı kalarak şunları elde edersiniz:

  • Sözdizimsel sürprizler yok. Veritabanınız (diğerleri gibi) SQL standardıyla %100 uyumlu değil - ancak bu Yesql için önemli değil. SQL eşdeğer sözdizimine sahip işlevleri aramak için asla zaman kaybetmezsiniz. Bir işleve asla geri dönmek zorunda kalmayacaksınız (raw-sql "bazı('funky'::SÖZDİZİMİ))").
  • En iyi editör desteği. Editörünüz zaten mükemmel SQL desteğine sahip. SQL'i SQL olarak kaydederek kolayca kullanabilirsiniz.
  • Takım uyumluluğu. DBA'larınız Clojure projenizde kullandığınız SQL'i okuyabilir ve yazabilir.
  • Daha kolay performans ayarı. Sorunlu bir sorgu için bir plan mı oluşturmanız gerekiyor? Sorgunuz normal SQL olduğunda bu bir sorun değildir.
  • Sorguları yeniden kullanma Aynı SQL dosyalarını diğer projelere sürükleyip bırakın çünkü bu sadece eski bir SQL'dir; sadece paylaşın.

Bana göre fikir çok havalı ve aynı zamanda çok basit, bu sayede proje pek çok şey kazandı takipçiler çeşitli dillerde. Ve bundan sonra, SQL kodunu ORM'nin çok ötesindeki her şeyden ayıran benzer bir felsefeyi uygulamaya çalışacağız.

IDE ve DB yöneticileri

Basit bir günlük görevle başlayalım. Çoğunlukla veritabanındaki bazı nesneleri aramamız gerekir; örneğin şemada bir tablo bulmamız ve yapısını (hangi sütunların, anahtarların, dizinlerin, kısıtlamaların vb. kullanıldığı) incelememiz gerekir. Ve herhangi bir grafiksel IDE'den veya küçük bir DB yöneticisinden, her şeyden önce tam olarak bu yetenekleri bekliyoruz. Böylece hızlı olur ve gerekli bilgileri içeren bir pencere çizilene kadar yarım saat beklemenize gerek kalmaz (özellikle uzak bir veritabanına yavaş bağlantı durumunda) ve aynı zamanda alınan bilgiler taze ve alakalı olur, ve önbelleğe alınmış önemsiz şeyler değil. Üstelik veri tabanı ne kadar karmaşık ve büyük olursa ve bunların sayısı da o kadar fazla olur, bunu yapmak da o kadar zor olur.

Ama genellikle fareyi atıyorum ve sadece kod yazıyorum. Diyelim ki "HR" şemasında hangi tabloların (ve hangi özelliklerle) yer aldığını bulmanız gerekiyor. Çoğu DBMS'de istenen sonuca, information_schema'dan gelen bu basit sorguyla ulaşılabilir:

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

Bu tür referans tablolarının içeriği, veritabanından veritabanına her DBMS'nin yeteneklerine bağlı olarak değişir. Ve örneğin MySQL için aynı referans kitabından bu DBMS'ye özel tablo parametrelerini alabilirsiniz:

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

Oracle bilgi_şemasını bilmiyor ancak var Oracle meta verilerive büyük sorunlar ortaya çıkmaz:

select table_name
     , pct_free       -- Минимум свободного места в блоке данных (%)
     , pct_used       -- Минимум используемого места в блоке данных (%)
     , last_analyzed  -- Дата последнего сбора статистики
     , ...
  from all_tables
 where owner = 'HR'

ClickHouse bir istisna değildir:

select name
     , engine -- Используемый "движок" ("MergeTree", "Dictionary" etc)
     , ...
  from system.tables
 where database = 'HR'

Benzer bir şey Cassandra'da da yapılabilir (tablolar yerine sütun aileleri ve şemalar yerine anahtar uzayları vardır):

select columnfamily_name
     , compaction_strategy_class  -- Стратегия сборки мусора
     , gc_grace_seconds           -- Время жизни мусора
     , ...
  from system.schema_columnfamilies
 where keyspace_name = 'HR'

Diğer birçok veritabanı için de benzer sorgular bulabilirsiniz (Mongo'nun bile özel sistem koleksiyonu, sistemdeki tüm koleksiyonlar hakkında bilgi içerir).

Elbette bu sayede sadece tablolar hakkında değil genel olarak her türlü nesne hakkında bilgi alabilirsiniz. Zaman zaman nazik insanlar bu tür kodları farklı veritabanları için paylaşırlar; örneğin, Habra'nın “PostgreSQL veritabanlarını belgeleme işlevleri” başlıklı makale serisinde (Ayb, Ben, Jimnastik). Tabii ki, tüm bu sorgu dağını kafamda tutmak ve sürekli yazmak o kadar keyifli ki, favori IDE/düzenleyicimde sık kullanılan sorgular için önceden hazırlanmış bir dizi snippet var ve geriye kalan tek şey, nesne adlarını şablona ekleyin.

Sonuç olarak, nesnelerde gezinmenin ve nesneleri aramanın bu yöntemi çok daha esnektir, çok zaman kazandırır ve bilgileri tam olarak gerekli olan biçimde (örneğin, gönderide açıklandığı gibi) almanızı sağlar. "Veri tabanından herhangi bir formattaki verileri dışarı aktarma: IntelliJ platformunda IDE'lerin yapabilecekleri").

Nesnelerle işlemler

Gerekli nesneleri bulup inceledikten sonra onlarla faydalı bir şeyler yapmanın zamanı geldi. Doğal olarak parmaklarınızı klavyeden ayırmadan.

Bir tabloyu silmenin neredeyse tüm veritabanlarında aynı görüneceği bir sır değil:

drop table hr.persons

Ancak tablonun oluşturulmasıyla daha ilginç hale geliyor. Hemen hemen her DBMS (birçok NoSQL dahil) şu veya bu şekilde "tablo oluşturabilir" ve ana kısmı biraz farklılık gösterebilir (ad, sütun listesi, veri türleri), ancak diğer ayrıntılar önemli ölçüde farklılık gösterebilir ve kullanılan tabloya bağlı olabilir. belirli bir DBMS'nin dahili cihazı ve yetenekleri. En sevdiğim örnek, Oracle belgelerinde "tablo oluştur" sözdizimi için yalnızca "çıplak" BNF'lerin bulunmasıdır 31 sayfayı kaplıyor. Diğer DBMS'lerin daha mütevazı yetenekleri vardır, ancak her birinin tablo oluşturmaya yönelik birçok ilginç ve benzersiz özelliği de vardır (postgres, mysql, hamamböceği, kötü olayları önceden haber veren kimse). Başka bir IDE'den (özellikle evrensel olandan) herhangi bir grafik "sihirbazın" tüm bu yetenekleri tam olarak kapsayabilmesi pek olası değildir ve yapabilse bile, cesareti zayıf olanlar için bir gösteri olmayacaktır. Aynı zamanda doğru ve zamanında yazılmış bir beyan tablo oluştur hepsini kolayca kullanmanıza, depolamayı ve verilerinize erişimi mümkün olduğunca güvenilir, optimum ve konforlu hale getirmenize olanak tanıyacaktır.

Ayrıca birçok DBMS'nin, diğer DBMS'lerde bulunmayan kendine özgü nesne türleri vardır. Üstelik, yalnızca veritabanı nesneleri üzerinde değil, aynı zamanda DBMS'nin kendisinde de işlemler gerçekleştirebiliriz; örneğin, bir işlemi "sonlandırmak", bir miktar bellek alanı boşaltmak, izlemeyi etkinleştirmek, "salt okunur" moduna geçmek ve çok daha fazlası.

Şimdi biraz çizelim

En yaygın görevlerden biri, veritabanı nesneleriyle bir diyagram oluşturmak ve nesneleri ve aralarındaki bağlantıları güzel bir resimde görmektir. Hemen hemen her grafiksel IDE, ayrı “komut satırı” yardımcı programları, özel grafik araçları ve modelleyiciler bunu yapabilir. Sizin için “ellerinden geldiğince” bir şeyler çizecekler ve siz de ancak konfigürasyon dosyasındaki birkaç parametre veya arayüzdeki onay kutularının yardımıyla bu süreci biraz etkileyebilirsiniz.

Ancak bu sorun çok daha basit, daha esnek ve zarif bir şekilde ve elbette kod yardımıyla çözülebilir. Herhangi bir karmaşıklıkta diyagramlar oluşturmak için, birkaç özel işaretleme dilimiz (DOT, GraphML vb.) ve onlar için bu tür talimatları okuyabilen ve bunları çeşitli formatlarda görselleştirebilen çok çeşitli uygulamalar (GraphViz, PlantUML, Mermaid) var. . Nesneler ve aralarındaki bağlantılar hakkında nasıl bilgi edineceğimizi zaten biliyoruz.

İşte PlantUML kullanılarak bunun nasıl görünebileceğine dair küçük bir örnek ve PostgreSQL için demo veritabanı (solda PlantUML için gerekli talimatı oluşturacak bir SQL sorgusu, sağda ise sonuç):

"Kod Olarak Veritabanı" Deneyimi

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'

Ve eğer biraz denersen, o zaman PlantUML için ER şablonu gerçek bir ER diyagramına çok benzer bir şey elde edebilirsiniz:

SQL sorgusu biraz daha karmaşıktır

-- Шапка
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'

"Kod Olarak Veritabanı" Deneyimi

Yakından bakarsanız pek çok görselleştirme aracının da benzer sorguları kullandığını görürsünüz. Doğru, bu istekler genellikle derinden Uygulamanın koduna "bağlanmıştır" ve anlaşılması zordur, bunların herhangi bir modifikasyonundan bahsetmiyorum bile.

Metrikler ve izleme

Geleneksel olarak karmaşık bir konuya geçelim: veritabanı performansının izlenmesi. Bana “arkadaşlarımdan birinin” anlattığı küçük, gerçek bir hikayeyi hatırlıyorum. Başka bir projede güçlü bir DBA yaşıyordu ve geliştiricilerden çok azı onu kişisel olarak tanıyordu veya onu şahsen görmüştü (söylentilere göre yan binada bir yerde çalıştığı gerçeğine rağmen) . Büyük bir perakendecinin üretim sistemi bir kez daha "kötü hissetmeye" başladığında "X" saatinde, Oracle Enterprise Manager'dan sessizce grafiklerin ekran görüntülerini gönderdi ve bu ekran görüntülerinde kritik yerleri "anlaşılırlık" için kırmızı bir işaretleyiciyle dikkatlice vurguladı ( en hafif tabirle bunun pek bir faydası olmadı). Ve bu "fotoğraf kartına" dayanarak tedavi etmek zorunda kaldım. Aynı zamanda, hiç kimsenin değerli (kelimenin her iki anlamında da) İşletme Yöneticisine erişimi yoktu, çünkü sistem karmaşık ve pahalıdır, birdenbire "geliştiriciler bir şeye rastlar ve her şeyi bozar." Bu nedenle geliştiriciler, frenlerin yerini ve nedenini "deneysel olarak" buldular ve bir yama yayınladılar. Eğer DBA'dan gelen tehditkar mektup yakın gelecekte tekrar gelmezse, o zaman herkes rahat bir nefes alacak ve mevcut görevlerine geri dönecektir (yeni Mektup'a kadar).

Ancak izleme süreci herkes için daha eğlenceli ve samimi, en önemlisi de erişilebilir ve şeffaf görünebilir. En azından ana izleme sistemlerine ek olarak temel kısmı (kesinlikle faydalıdır ve birçok durumda yeri doldurulamaz). Herhangi bir DBMS'nin mevcut durumu ve performansı hakkında bilgi paylaşımı serbestçe ve kesinlikle ücretsizdir. Aynı "kanlı" Oracle DB'de, performansla ilgili hemen hemen her türlü bilgi, süreçlerden ve oturumlardan arabellek önbelleğinin durumuna kadar sistem görünümlerinden elde edilebilir (örneğin, DBA Komut Dosyaları, "İzleme" bölümü). Postgresql ayrıca bir dizi sistem görünümüne sahiptir. veritabanı izlemeözellikle herhangi bir DBA'nın günlük yaşamında vazgeçilmez olanlar, örneğin pg_stat_activity, pg_stat_database, pg_stat_bgwriter. MySQL'in bunun için ayrı bir şeması bile var. performans_şema. A Mongo'da yerleşik profil oluşturucu performans verilerini bir sistem koleksiyonunda toplar sistem.profil.

Böylece, özel sql sorguları gerçekleştirebilen bir tür metrik toplayıcı (Telegraf, Metricbeat, Collectd), bu metriklerin depolandığı (InfluxDB, Elasticsearch, Timescaledb) ve bir görselleştirici (Grafana, Kibana) ile donatılmış olarak, oldukça kolay bir şekilde elde edebilirsiniz. ve sistem çapındaki diğer ölçümlerle (örneğin uygulama sunucusundan, işletim sisteminden vb. elde edilen) yakından entegre olacak esnek bir izleme sistemi. Örneğin bu, InfluxDB + Grafana kombinasyonunu ve ayrıca erişilebilen sistem görünümlerine yönelik bir dizi sorguyu kullanan pgwatch2'de yapılır. özel sorgular ekle.

Toplam

Ve bu, normal SQL kodunu kullanarak veritabanımızla neler yapılabileceğinin yalnızca yaklaşık bir listesidir. Eminim daha birçok kullanım alanı bulabilirsiniz, yorumlara yazın. Ve tüm bunları nasıl (ve en önemlisi neden) otomatikleştireceğimizi ve bir dahaki sefere bunu CI/CD ardışık düzeninize nasıl dahil edebileceğinizi konuşacağız.

Kaynak: habr.com

Yorum ekle