Používáme databáze for fun and profit
💽

Používáme databáze for fun and profit

Myslím, že celý obor programování má ADHD a shiny new toy syndrom. To asi není nic extra zvláštního, když si vezmeme, že my vývojáři jsme inteligentní a kreativní lidé, kteří si rádi hrajeme a čirou náhodou jsme se přichomýtli k další industriální revoluci. Jen ne s parou a pákou, ale s tranzistorem a kompilátorem.

Vlastně už 15 let sleduju, že se vývojáři snaží opustit SQL (hlavně MySQL a Postgres) bez toho, aby k tomu měli extra dobrý důvod. Na to, co potřebují ukládat a vytahovat, jsou tyhle databáze dost rychlé, dost silné, dost známé každému absolventu VŠ a obecně podporované editory, knihovnami.

Před 15 lety se hodně mluvilo o škálovatelnosti a CAP theorému. Moderní byl Riak a CoachDB. O map-reduce vycházely články každý týden. Všichni jsme se těšili na to, jak budeme provozovat stovky instancí a psát map-reduce joby.

Neměl bych si na tu dobu moc stěžovat, protože Riak mě dostal k Erlangu a ten následně k Clojure, které mi změnilo život.

No a pak se začalo mluvit o Mongu, Redisu (který nahrazoval spíš memcached). Do toho lidi experimentovali s grafovými databázemi (asi úspěšně, když jsem žil v USA, opakovaně jsem potkával sportovní auta s Neo4J - buď tax evasion as a marketing budget, nebo šťastný majitel), dokumentovými (TerminusDB), skladišti na data (Cassandra), fulltexty na steroidech (Elastic) atd.

Během té doby byl Postgres mnohokrát prohlášen za mrtvého. Vlastně jediné dvě technologii, které znám, které někdo označil víckrát za mrtvé, jsou Bitcoin (neprávem) a Linux na desktopu (právem).

Do toho je ten nekonečný dojem lidí, že SELECT title, url, contents FROM articles WHERE active = 1 smrdí a musí se napsat něco jako: articlesRepository.where(active = 1).select([title, url, contents].execute(), případně:

class Article < ApplicationRecord
  scope :active, -> { where(active: 1) }
end

class ArticlesController < ApplicationController
  def index
    @articles = Article.active.select(:title, :url, :content)
  end
end

Protože se lidi snažili ty databáze pod tím schovat.

Já si myslím, že tohle se zase změnilo. Minimálně v mé bublině vidím teď jen dva mainstream tábory:

Tábor 1: JavaScript na serveru i na frontendu. Potřebuju pushovat změny do klienta v reálném čase (Debezium, Websockets, remult), vše je SPA a nebo mobilní appka (často v React Native).

Tábor 2: This is fine!

image
WITH active_articles AS (
  SELECT id, title, url, content, author_id
  FROM articles
  WHERE active = true
),
article_stats AS (
  SELECT
    article_id,
    COUNT(*) AS comment_count,
    AVG(rating) AS average_rating
  FROM comments
  GROUP BY article_id
),
ranked_articles AS (
  SELECT
    a.id,
    a.title,
    a.url,
    a.content,
    s.comment_count,
    s.average_rating,
    RANK() OVER (ORDER BY s.average_rating DESC) AS rating_rank
  FROM active_articles a
  LEFT JOIN article_stats s ON a.id = s.article_id
)
SELECT
  ra.id,
  ra.title,
  ra.url,
  ra.content,
  COALESCE(ra.comment_count, 0) AS comment_count,
  COALESCE(ra.average_rating, 0) AS average_rating,
  ra.rating_rank,
  author.name AS author_name,
  author_profile.bio AS author_bio
FROM ranked_articles ra
LEFT JOIN LATERAL (
  SELECT u.name, p.bio
  FROM users u
  JOIN profiles p ON u.id = p.user_id
  WHERE u.id = ra.author_id
) AS author ON true
ORDER BY ra.rating_rank;

Třetí tábor je specifický pro Clojure a to jsou uživatelé Datomicu a XTDB. Jsou to “naše databáze”, které umožňují psát kód typu:

(xt/submit-tx node [[::xt/put
                     {:xt/id :person-1
                      :name "John Doe"
                      :age 30}]])
(def query
  {:find '[e]
   :where '[[e :name "John Doe"]]})

(xt/q (xt/db node) query)

Ale to si dovolím ignorovat. Ty dvě databáze jsou pecka na některé use cases, ale nejsou mainstream.

Já určitě patřím do toho tábora číslo 2.

Za těch 15 let Postgres efektivně nahradil:

  • NoSQL databáze (JSON a JSONB datové typy)
  • Time series databáze (Timescale)
  • Columnar storage (cstore_fdw a zheap)
  • GIS databáze a Geospatial Analysis (PostGIS)
  • Full-text search (tsvector a tsquery)
  • Grafové databáze (pg_graph)
  • Vektorové databáze (ok, pgvector není production ready, ale bude)
  • KV store (HStore a JSONB)
  • Analytické databáze (cstore_fdw again)
  • OLAP (Citus)
  • Streaming a real-time procesování dat (pglogical)
  • Machine Learning (MADLib)
  • Datové integrace a ETL (na to ani není potřeba rozšíření)
  • Compliance a Auditing (pgaudit)
  • Data versioning a Temporal databases (temporal_tables, bitemporal, pgmemento)

Vlastně když bych se dokázal naklonovat, tak jeden z mých klonů by nejspíš nedělal nic jiného, než se učil Postgres. 😃

Co teda jako navrhuješ?

Měli byste narvat všechnu business logiku do PL/SQL? Měli byste se zbavit Monga a Redisu?

Upřímně, to bych tak úplně neřekl.

Můj návrh je:

  • Používejte dál, co vám funguje.
  • U příští aplikace, pokud je Postgres vhodný, tak ho zkuste.
  • Namodelujte si dobře datový model.
  • Použijte vlastnosti Postgresu k tomu, aby se k datům dostali uživatelé, kteří se k nim dostat mají a aby byla data konzistentní.
  • Tam, kde se vyplatí použít pokročilé vlastnosti, jako třeba i pokročilejší napsané dotazy, views, materializované views a různá rozšíření, která jsem zmínil. Cílem je rychlost a nevynalézání kola.
  • Nad to dejte nějaký váš běžný backend jazyk a business logiku spíš mějte tam. Pokud chcete na většinu operací ORM, mějte ORM. Pokud nechcete ORM, nemusíte.
  • Průběžně školte své kolegy v tom, aby uměli navrhnout databázi, napsat dotazy, a taky databázi monitorovat a vylepšovat. Při nabírání nových zaměstnanců testujte i jejich znalost SQL.