Jak funguje cache v relační databázi?

Jak funguje cache v relační databázi?
« kdy: 01. 03. 2023, 23:32:17 »
Zdravím,

řekněme, že mám databazí a v ní tabulku s nutričními hodnotami potravin: FoodsTable.

Uživatelé na frontendu často potravinami listují, když vyhledávají fulltextem. A řekněme že tento query spouštím jako parametrized query:

Kód: [Vybrat]
var pstmt = con.prepareStatement("SELECT * FROM FoodTable WHERE name like CONCAT( '%',?,'%')");
pstmt.setString(1, notes);
var rs = pstmt.executeQuery();

Databáze bude řekněme Postgres a celkový objem dat v tabulce FoodTable bude řekněme 50MB.

Tzn. otázka zní, má v takovém případě vůbec smysl uvažovat o nějaké In memory cache přímo v Javovské aplikaci, když už relační databáze na své straně umí cachovat? A jak to vlastně ta databáze cachuje, drží si výsledky toho query in-memory, nebo to funguje jinak?

PS: Např. SQLite cachovat umí, ale těžko to je In-Memory cachování, spíše si tu cache nějak zapisuje na disk do souboru.


Re:Jak funguje cache v relační databázi?
« Odpověď #1 kdy: 02. 03. 2023, 00:10:56 »
S Postgresem přímo nedělám, ale třeba z MS SQL vím, že „cache“ (nebo obecně to, co se jí rozumí) si prostě nahrne do RAM postupně (jak se to načítá a používá) maximum obsahu z disku a místo Physical Reads pak dělá Logical reads, což je sice cool, ale ne ideální, lepší je navrhnout korektně index(y). U takhle „malé“ tabulky ten index imho nebude mít zásadní vliv (záleží, jak často se to má volat, ale tohle by mělo být jak nic), takže se to nacachuje celé do RAM a bude se to skenovat v RAM, ne z disku. Při velkých objemech dat ale může být i to čtení z RAM znát, vytěžuje to CPU, protože se snaží chybějící indexy nahradit hrubou silou kolikrát (podle množství dat) i paralelizací Full scanu tabulky (nejsem vývojář, spíš dba, takže úplně nevím, jak moc by třeba tady zabral index dle sloupce name na tenhle like, by se muselo zkusit a prohlédnout exekuční plány, ale od pohledu je to první index, který by mě napadlo zkusit vytvořit).

Anebo se tu hovoří o jiné cache a já jsem úplně mimo ;).

alex6bbc

  • *****
  • 1 637
    • Zobrazit profil
    • E-mail
Re:Jak funguje cache v relační databázi?
« Odpověď #2 kdy: 02. 03. 2023, 05:31:37 »
pokud se tabulka nemeni a vlastne read-only, tak bych si cache udelal. kazde data z db po dotazu, bych ulozil do ram a primarne hledal v ram, jen kdyz by to v ram nebylo, tak bych to tahal z db. tim by se mi casem cache naplnila a uz by to ficelo jen z ramky.

Re:Jak funguje cache v relační databázi?
« Odpověď #3 kdy: 02. 03. 2023, 07:24:06 »
Zdravím,

řekněme, že mám databazí a v ní tabulku s nutričními hodnotami potravin: FoodsTable.

Uživatelé na frontendu často potravinami listují, když vyhledávají fulltextem. A řekněme že tento query spouštím jako parametrized query:

Kód: [Vybrat]
var pstmt = con.prepareStatement("SELECT * FROM FoodTable WHERE name like CONCAT( '%',?,'%')");
pstmt.setString(1, notes);
var rs = pstmt.executeQuery();

Databáze bude řekněme Postgres a celkový objem dat v tabulce FoodTable bude řekněme 50MB.

Tzn. otázka zní, má v takovém případě vůbec smysl uvažovat o nějaké In memory cache přímo v Javovské aplikaci, když už relační databáze na své straně umí cachovat? A jak to vlastně ta databáze cachuje, drží si výsledky toho query in-memory, nebo to funguje jinak?

PS: Např. SQLite cachovat umí, ale těžko to je In-Memory cachování, spíše si tu cache nějak zapisuje na disk do souboru.

V databázi je několik různých cache - třeba v Postgresu - máte sdílenou cache datových stránek, lokální type cache, lokální cache plánů předpřipravených dotazů. Postgres necacheuje výsledky dotazu - ale v share buffers má data, které potřeboval pro zpracování dotazu a opakovaně (pokud zůstanou v cache) už je nečte z file systému (kde je další cache).

Přístup do lokální cache je výrazně rychlejší než přístup do Postgresu nebo jakékoliv jiné SQL databáze(minimálně o řád, ale možná ještě o víc). Jakmile přistupujete k databázi, tak máte režii síťové vrstvy, parseru, executoru (i když používáte prepared statements). Navíc v relačních databázích je dost velká režie zajištění konzistence dat - proto se používají i inmemory databáze jako je redis, kde je sice síťová režie, ale nulová režie s konzistencí a malá režie s protokolem.

Pokud neřeším konzistenci dat, tak je lokální cache vždy výhra (pokud se mi data vejdou do RAM, a pokud budu mít zahřátou cache). Jakmile se začne řešit konzistence dat - tak použití lokální cache (zvlášť jsou data v cache delší dobu) tak je spíš problém - musíte řešit jak synchronizovat data, jak zamykat data (když máte víc aplikačních serverů), jak optimálně zahřát cache, kdy invalidovat cache, ...

V praxi se používá mix - některá data se dobře kešují lokálně, jiným je dobře v redisu -  a zbytek se nechává v databázi a lokální cache se použije maximálně v rámci transakce. Hodně záleží na očekávané zátěži - i bez lokální cache a se správnými indexy může databáze vracet dotazy v řádech ms, což pro většinu aplikací bohatě stačí.

Jinak on ten přístup do RAMky také není nekonečně rychlý - pro trochu větší data se musí použít hash tabulky nebo stromy, a s tím je spojená nějaká režie (ať už CPU nebo RAM).

Re:Jak funguje cache v relační databázi?
« Odpověď #4 kdy: 02. 03. 2023, 09:13:48 »
Jako teoretická otázka je to zajímavé, ale pro praktické použití na to jdete z úplně špatného konce.

Pro praktické použití si položte otázku, zda řešení bez cahce představuje nějaký problém. Je to pomalé, nedodržíte SLA? Nebo máte vysoké náklady na provoz DB a potřebujete je snížit? Pak řešte, jak to zrychlit nebo snížit náklady na provoz DB. Cache v aplikaci je pak jen jedno z mnoha řešení, je potřeba vybrat to nejlepší. Žádný takový problém neřešíte? Pak neřešte žádnou cache, je to klasický příklad předčasné optimalizace – a jediné, čeho dosáhnete, bude zesložitění kódu a více chyb. (Ne nadarmo se říká, že invalidace cache je jeden ze dvou největších problémů při programování. Ten druhý je správné pojmenování.)


Re:Jak funguje cache v relační databázi?
« Odpověď #5 kdy: 02. 03. 2023, 11:29:05 »
Měl jsem představu, že tyhle věci fungují tak nějak samotížně. V relační databázi hlavně hleďte oindexovat všechno, podle čeho vazbíte nebo vyhledáváte. Toto je otázka návrhu datové základny = součást tvorby aplikace. A dejte RDBMS dostatek RAM. On by pak měl mít přirozený sklon, držet v RAMce všechno, co do ní jednou načetl (v interních strukturách, které k tomuto používá). V situaci, kdy má DB na disku větší velikost, než je objem RAM dostupný RDBMS, budou se "data cachovaná pro čtení" podle potřeby uvolňovat z RAMky nějakým LRU mechanismem.

Ještě pokud se týče indexace, tak bych možná rozlišoval mezi indexováním databázových klíčů, a indexací rozsáhlejších textů (např. popisů produktů) pro fulltextové vyhledávání - může se jednat o dvě různé disciplíny s různými nástroji.

Cache na straně DB klienta přenechám povolanějším, ostatně už se jich tu několik ozvalo :-)

P.S. na latence dotaz-odpověď (při větším počtu sériově řazených dotazů = blbě napsaná aplikace) má vliv nastavení CPU C-states. Pokud si hardware provozujete sám, mrkněte do BIOSu, případně se to dá třeba v Linuxu poladit v kernel cmdline.
« Poslední změna: 02. 03. 2023, 11:32:47 od František Ryšánek »