Nagy mennyiségű adatot (több millió rekord) szeretnék cahe-elni és erre keresek valami jó módszert.
A fejlesztési környezet MySql és Java EE 7 (GlassFish).
Van egy kereskedelmi rendszer ahol termékeket értékesítenek. A termékek mozgása egy táblában található. Vannak különböző mozgásnemek melyek növelhetik, csökkenthetik a készletet vagy nincs készlet hatásuk.
Pl:
FORGALOM
ID_CIKK
DATUM
MENNYISEG
EGYSEGAR
Szükség van kimutatások készítésére egy adott időszak forgalmáról. Mennyi volt az adott időszak elején a nyitó készlet, mennyi volt a növekedés, csökkenés, a forgalom valamilyen módon számított fogyasztói és beszerzési árakon (többféle módon lehet számolni ez lényegtelen most a probléma szempontjából)
Jelenleg tervek szerint úgy működne a dolog, hogy egy éjszaki job leválogatja, hogy egy adott terméknek adott napon volt-e bármilyen mozgása és azt beleteszi egy cache táblába és a kimutatások már ebből a táblából dolgoznának.
Pl: ha egy adott termékből volt egy nap 300 vevőnek eladás egy 1 beszállítótól beszerzés, akkor az a cache táblában egy soron fog megjelenni,
pl. reszelt tejszínhab, csökkenés 1300 db, növekedés 200 db, adott napi mozgás -1100 db. Ezen kívül még kiszámolom hogy mennyi volt az aznapi nyitó készlet, záró készlet, illetve készlet értéket.
Ez mind szép és jó, addig amíg nem akarja a listákat úgy lekérni, hogy benne legyen a mai dátum, mert úgy a job éjszaka fut és csak az előző napig vannak benne az adatok.
Most én négy módszert látok a probléma megoldására:
1;
Ha listákat úgy készítem el, hogy ha a mi dátum is benne van a szűrő paraméterekben akkor egyrészt dolgozok a cache táblából, a mai adatokat pedig a többi táblából szedem össze. Így bonyolult lesz a kód, másrészt ha bármilyen változtatást kell eszközölni az üzleti logikában akkor azt minden kimutatáson át kell vezetni.
2;
Futhat egy job is amely x percenként az újonnan keletkezett adatokkal frissíti a cache táblát, de itt megint fennáll a veszélye annak hogy nem kap releváns adatot. pl. 15 perces a frissítési ciklus és az utolsó óta történt valami nagyobb készletmozgás.
3;
Ha a felhasználó kér egy listát és a szűrés a mai napra is vonatkozik, csak abban az esetben frissítem a cache táblát az újonnan keletkezett adatokkal. Talán ezt tűnik a legjobb módszernek. Ha még nem volt az adott tételből mozgás aznap, akkor bele insertálom a cache táblába, ha már volt mozgás akkor csak updatelem a rekordot az új értékkel. Csak itt meg akkor lehet gond ha sok user kezd el kimutatásokat készíteni. Egyszerre rengetegszer lesz lekérve az aznapi forgalom és insertálva/updatelve a cache táblába.
4;
a 2. és 3. kombinációja.
Melyik módszert érdemes használni, vagy van e erre esetleg valami jó design pattern.
- 1352 megtekintés
Hozzászólások
A "több millió rekord" önmagában még nem tényező, ha a táblák jól vannak szervezve és az indexek száma és tartalma jól van balanszírozva és a támogató memóriacache is megkapta a szükséges tuningot.
Cache (vagy MQT - https://community.toadworld.com/platforms/ibmdb2/w/wiki/7223.materializ…) táblát csak abban az esetben használnék (pontosan a felsorolt aggályok miatt), ha a fentiek valamiért nem teljesíthetők - ez a ritkább eset.
Ha fennáll a veszélye a riport szükségtelen klikkelgetésének, vagy időzítővel meg kell oldani, hogy csak x másodpercenként legyen startolható, vagy flagelni, hogy a következő csak akkor, ha az előző már nem fut, vagy adott pillanatban csak n-szeri futását engedélyezni.
- A hozzászóláshoz be kell jelentkezni
Egy lehetőség, hogy van a termék táblában egy aktuális mennyiség oszlop, és a mozgásoknak van egy másik táblája (termék, dátum, delta) oszlopokkal. Utóbbi táblából termék és dátum szerint csoportosítva, deltát összegezve kijönnek a napi mozgások, egy termék aktuális készlével összevetve pedig látod, hogy melyik nap mennyi volt a készlet (ezt már kódból számolnám, ha megvan a többi adat SQL-ből). Nem gondolom, hogy pár millió sor esetén ez kezelhetetlen lenne. De van az úgy, hogy a denormalizált adatszerkezet a célrevezető, és a mozgások táblában lenne egy oszlop a mozgás utáni aktuális készlettel. Csak arra kell figyelni, hogy ezek a megoldások lockolással járnak, viszont nem mondtad, hogy egetverő lenne az írások gyakorisága. A módszer előnye, hogy az élő táblában ott van minden adat, ami a lekérdezéshez kell.
Ha így lassú a query mert pl. szar a hardver, akkor a következő ötlet egy materialized view vagy hasonló (ezt hívod cache táblának, de az a lényeg, hogy egy jó RDBMS ezt adja neked ingyen, nem neked kell megírni). Ezt akár óránként vagy sűrűbben is lehet automatizáltan frissítgetni. Ha ez nem elég friss, akkor a view-ból kérdezed le a korábbi adatokat és melléteszed a view frissítése utáni változásokat (de ez csak akkor lesz jó, ha utóbbi halmazba kevés adat kerül).
Ilyen kis adatmennyiségnél én nem feltétlenül mennék bele bonyolultabb kódolásokba, memcached használatába vagy ilyesmi. De lenne ötletem arra is.
- A hozzászóláshoz be kell jelentkezni
Ja egy hasonló ötlet: a termékmozgás táblában legyenek egyedi és aggregált sorok termékenként. Lenne egy háttérfolyamat, ami időről időre fog egy csomó egyedi mozgást, összegzi őket, elmenti az összeget, és archiválja az egyedi sorokat. Ezt így könnyű sql-ből lekérdezni és tuti gyors lesz. (Ugyanezt csinálja minden time series adatbázis: régebbi adatok időbeli felbontása csökken, de a séma ugyanaz marad.)
- A hozzászóláshoz be kell jelentkezni
Én is hasonlóan csinálnám. Ha az adatokat is az mind az én programom írja, akkor esetleg megcsinálnám, hogy már az írás tranzakcióján belül frissüljön az aggregált adat, és akkor biztosan mindig friss a lekérdezés eredménye.
- A hozzászóláshoz be kell jelentkezni
Kimondottan erre jók a triggerek. Minden táblába insert-elés után lefuttat egy insert or update-et az aggregált adatokra is és csókolom. A teljes logika a db szerveren belül marad.
Vizsgára felkészülés végett keresek "kidobásra" szánt menedzselhető Cisco switch-eket és routereket, leginkább Pest és Bács-Kiskun megye területén.
- A hozzászóláshoz be kell jelentkezni
Persze, azzal is lehet csinálni, függően attól, hogy kinek milyen kalapácsa van :-). Annyiból jobb, mint az általam javasolt, hogy az jól megcsinálva akkor is működik, ha az adatokat több különböző program is írja.
- A hozzászóláshoz be kell jelentkezni
Igen, ezért is javasoltam többször is. Ha már a db szerver biztosítja azt, hogy automatikusan aggregáljon, akkor érdemes kihasználni, mivel így a kódot elég egy helyen karbantartani, és így frontend oldalon nem kell több különböző kódbázisba belenyúlni, ha éppen az alkalmazás olyan, hogy pl van neki webes, desktop és valamilyen egyéb felülete is.
Vizsgára felkészülés végett keresek "kidobásra" szánt menedzselhető Cisco switch-eket és routereket, leginkább Pest és Bács-Kiskun megye területén.
- A hozzászóláshoz be kell jelentkezni
A MySQL-nel van memory táblatípusa, illetve van memcached is. Mindenképp az appod fogja tudni, hogy minek kell cache-ben lennie.
- A hozzászóláshoz be kell jelentkezni
Szóval egyik helyen történik valami, amit egy másik helyen is fel kellene dolgozni, lehetőleg kis késleltetéssel. Akkor ha történik csökkenés vagy növekedés küldesz egy eventet az iránnyal, a mennyiséggel, meg az új összmennyiséggel, és ezeket az eventeket figyeli egy listener. A listener meg updateli az adott napi rekordot, így mindig friss.
- A hozzászóláshoz be kell jelentkezni
Nekem ket megoldas jut hirtelen az eszembe:
1. Egy tablaban nyomonkovetni az arumozgast. Pl.
Ido (unix epoc), termek-id, mennyiseg, tranzakcio-tipus (eladas/vetel)
Definialni egy ido ablakot es az ennel regebbi adatokat arhivalni/torolni etc
2. Az arumozgast elasticsearchben vagy time-based db-ben tarolni. Elasticsearch eseteben meg a vizualis megjelenites is egyszeru.
Szerk: time-based az time series akart volna lenni. Elnezest.
- A hozzászóláshoz be kell jelentkezni
Én a helyedben tuti csinálnék egy triggert az adattáblára. Új sor beszúrásakor pedig a triggerrel frissíteném a cache tábla adatait. Ezzel a megoldással a cache csak akkor frissül, amikor kell, a db-re nézve pedig live adatok lennének benne.
Vizsgára felkészülés végett keresek "kidobásra" szánt menedzselhető Cisco switch-eket és routereket, leginkább Pest és Bács-Kiskun megye területén.
- A hozzászóláshoz be kell jelentkezni
A "több millió" rekord az semmi, bocs.
Javaslom, hogy először is csináld meg a reportot generáló SQL-t úgy, hogy a live adatokból dolgozik (valami ilyet kérnek, nem?), tuningold kicsit, s nézd meg, mennyi idő alatt készül el.
Ha napi report, akkor még 5 percnyi futásidő is oké lehet, de ezt neked kell tudnod :-)
Jól megválaszott indexekkel és táblaszerkezettel több _milliárd_ soros táblákból joinolgatva, aggregálgatva is lehet 38 sec alatt reportot generálni. Szal mindent lehet.
- A hozzászóláshoz be kell jelentkezni
Maga az irány azért lehet jó, hogy ne dolgoztassuk halálra szegény sql szervert. Megfelelően indexelve valószínűleg az aggregálás tényleg gyorsan lefuthat egy pár millió rekordos táblán, de ha már az elején okosan csinálja, akkor később nem kell a sok száz milliós/milliárdos rekordszámnál azon aggódni, hogy hogyan gyorsítson rajta.
Vizsgára felkészülés végett keresek "kidobásra" szánt menedzselhető Cisco switch-eket és routereket, leginkább Pest és Bács-Kiskun megye területén.
- A hozzászóláshoz be kell jelentkezni
Ez a rendszer már működik, vagy még tervezés alatt van? Mérések alapján gondolod, hogy ez a szűk keresztmetszet, vagy csak tipp?
- A hozzászóláshoz be kell jelentkezni