Fork me on GitHub
#clojure-norway
<
2024-02-03
>
slipset15:02:32

Så borti en tråd her kom jeg i skade for å snakke om databaser, og da kommer jo som alltid @christian767 innom og sier Datomic 🙂

🙈 2
cjohansen15:02:56

Forsøksvis litt på egen bekostning, men ser at jeg allikevel deraila dere, beklager det!

slipset15:02:31

Absolutt ikke noe å beklage. Jeg setter veldig stor pris på det, fordi det får meg til å tenke.

slipset15:02:40

Og det fikk meg til å tenke litt.

slipset15:02:48

Fordi vi bruker ikke Datomic.

slipset15:02:10

Men, det er ting jeg har tenkt som hadde vært kult a gjøre, som ikke gir oss Datomic, men som kanskje ville gi noe av det andre. En viktig greie for meg er at i Datomic så er lesing ansett som bivirkningsfri, mens skriving ikke er det. Som regel når man snakker med en “vanlig” database, har man en connection, og på den connection kan man både lese og skrive. En tanke jeg har lekt meg med er å skille på disse to. Så vi ser fra over at vi i Ardoq sender rundt en ctx som holder database connections. Det som hadde vært litt kult hadde vært å hatt en readonly-ctx og en mutating-ctx hvor førstnevnte bare inneholdt readonly connections til databsen. Og man kunne da, ansett funksjoner som brukte readonly-ctx som bivirkningsfrie, modulo noe isolation-level styr og riktig bruk av transactions og sånt.

1
terjesb15:02:54

Enig, høres ut som en god ide. Også uten Datomic kan man da skille mellom en primary-conn for skriving og replica-conn for lesing (selv om de i utgangspunktet går mot samme). Med Datomic så trenger man en ‘conn’ for å skrive, ellers en ‘db’ for å lese.

cjohansen15:02:10

Det ville i det minste isolert skriving. MEN! En viktig grunn til at les i datomic kan anses som bivirkningsfritt er at du leser fra en immutable verdi. Hvis du feks logger basis-t fra den kan du alltid gjenskape enhver situasjon. Det vil du ikke få til på samme vis med en connection.

slipset15:02:29

Det er korrekt.

cjohansen15:02:18

Utover det er jeg enig i at å skille dem gir deg bedre kontroll og oversikt

slipset15:02:20

Men det jeg synes er kult med Datomic diskusjonene er å dekonstruere hvorfor den er bra, for så å se i hvilken grad man trenger alle bitene og om det er biter av bra man kan anvende med andre databaser.

👍 2
cjohansen15:02:38

Absolutt, fin måte å la seg inspirere på

slipset15:02:17

Og selvsagt er det sånn at siden det meste er turingkomplett, så kan man gjøre alt med alt, men dog med ulike grader av ergonomi.

cjohansen15:02:21

@U04V5VAUN stemmer. Derfor syns jeg det er mer interessant å diskutere hvilke ting en teknologi gjør lett og åpenbart og hva som er vanskelig, når man sammenligner epler og pærer

terjesb16:02:47

En av ukas frustrasjoner med PG: La til en kolonne i en tabell, etterfylte med data. En trigger gjorde så jobben sin og endret updated_at på samtlige rader. Teknisk korrekt, men.. føler at den også ødela litt. Datomic gir automatisk “updated_at” per datom/attributtverdi, fordi alle endringer gjøres som transaksjoner og hver transaksjon får en txInstant. Liker! (På den annen side har ikke Datomic en updated-at på selve entiteten. Det kan løses på flere måter, hvis man virkelig trenger det. Avhengig av hva man trenger det til, kan det også være helt andre løsninger som er bedre.) En av ukas gleder med Datomic: Slet litt med performance på en POC, litt N+1 mot PG. Importerte dataene til Datomic istedenfor. Responstiden gikk ned fra 5000+ ms til 125 ms.. og kunne beholde N+1 med pull istedenfor select;) En annen glede. Datomic lagrer ikke nil. Eksperimenterte med også å droppe 0 for et subsystem. Reduserte fra 9 millioner til 3 millioner datoms! Det er betydelig ift. indeksering, minnebruk og dermed caching/performance. Ellers alltid gøy å lage transaksjoner hvor man oppretter flere entiteter som koples sammen. Istedenfor å opprette “primær” row, sjekke generated keys og bruke disse i “secondary” rows, så kan man med Datomic sende hele greia som én datastruktur:

[
{:db/id "primær"
 :primær/primær-id (random-uuid)
 :primær/primær-navn "Primært"}
{:db/id "sekundær"
 :sekundær/sekundær-id (random-uuid)
 :sekundær/sekundær-navn "Sekundært"
 :sekundær/primær "primær"}
{:db/id "datomic.tx"
 :minapp.tx/kilde :manuelt
 :db/doc "Eksempel på å opprette koplede entiteter, uten å bruke isComponent."}
]
Hvor strengen "primær" funker som en midlertidig entitetsid, slik at Datomic genererer en E og skjønner at det er samme E som skal brukes begge steder. datomic.tx kan brukes for å putte ting rett på tx-en. Love it. Denne transaksjonen oppretter 3 entiteter: • primær • sekundær, som har et ref-attributt som peker til primær (primær kan senere finne sine sekundære via en implisitt reverse understrek-link, :sekundær/_primær) • transaksjonsentitet; som automatisk får en txInstant + at alle 8 datomene i hele transaksjonen har en implisitt ref til denne via sin (EAV)T. Eksempel på en reified transaksjon, hvor vi også putter på metadata. Mange spennende anvendelser. (Hvis man ikke hadde tatt med datomic.tx, så ville Datomic selv opprettet denne med txInstant.) Lærte for øvrig også om db/match-partition for å optimalisere samlokalisering av entiteter. La oss si at man på forhånd har en rot-id (som selvsagt kan være en eid/ident/lookup ref) og ønsker at “primær” og “sekundær” bør ligge nært med roten i indekssegmenter:
{:db/match-partition {"primær" rot-id
                      "sekundær" rot-id}
(Beklager langt innlegg, blogger foreløpig ikke:)

❤️ 2
Ivar Refsdal19:02:07

https://github.com/vvvvalvalval/datomock comes to mind (har ikkje brukt det noko særleg sjølv, men interessant bibliotek.) Ser at f.eks. postgres har moglegheit for https://jdbc.postgresql.org/documentation/use/#connection-parameters. Det var nytt for meg. Men den read only connectionen får vel neppe lest pending transaksjoner ein kanskje har gåande (i samme tråd) i mutating-ctx (?) (kanskje mogleg å skru på dette, men ja...) Imponerande at Datomic slår PG på ytelse @U0523NZUF Kvar leste du om db/match-partition?

terjesb09:02:05

Må sies at det var epler og pærer i den ytelsessammenligningen, likevel interessant. Ang match-partition. Skulle tro jeg så det nevnt i #datomic, men finner ikke igjen noen referanse der nå, eller på forum eller ask. Generelt snakker favila/Shortcut en del om partisjonering, og tror de har dekantert hele databasen minst én gang for å regenerere med nye eids for bedre lokalitet. favila var nylig på en podcast, kanskje der. Kan ikke utelukke at jeg så den tilfeldigvis i dokumentasjonen inspirert av partisjoneringsdiskusjonene i #datomic:) Søk der etter ‘favila partition’ for litt snacks. Så lenge man er på én server, er det neppe viktig. https://docs.datomic.com/pro/transactions/transactions.html#partition-assignment https://blog.datomic.com/2023/04/implicit-partitions.html https://clojurians.slack.com/archives/C03RZMDSH/p1682029846944639

Ivar Refsdal12:02:02

TIL ordet https://naob.no/ordbok/dekantere Fritt etter hugsen så var det ein gist frå Favila som inspirerte meg til å skriva https://github.com/ivarref/rewriting-history, eller den satt meg på ideen iallefall. (Det støttar forøvrig ikkje partisjonar.) > Så lenge man er på én server, er det neppe viktig Er du sikker? Eg kan ikkje nok(o) om dette, men mi enkle forståing er at f.eks. om noko vert mindre og mindre relevant over tid, så kan det gje meining å gje partisjon som f.eks. YYYY-mm til entitetar. Vil ikkje det halda oppe ytelsen (cache hit) dersom ein typisk søker på ting som vart oppretta siste 12 månadar?

Ivar Refsdal12:02:40

Favila burde skriva bok om datomic 🙂

💯 2
terjesb12:02:42

> Så lenge man er på én server, er det neppe viktig Tankegangen min var at så lenge du er på en server og har alt lokalt (inkl storage eller valcache), så har du alle indekssegmentene også lokalt, og får det kanskje fra buffer eller noe sånt. Tenkte at det med partisjonering er viktigere i forhold til at en peer kan minimere antall indekssegmenter den trenger å hente fra storage/cache over nett. Hvis man i tillegg klarer å rute backend-trafikk til en peer som håndterer aktuell partisjon, vil peeren typisk allerede ha mange segmenter lokalt. Enig i at smart partisjonering gir bedre ytelse også på små systemer:)

👍 1