Üdv!
Van egy Django alapú weboldal az egyik partnerünknél, ami mostanában eléggé lelassult. Django debug toolbar-ral megnézve azt találtam, hogy 50 elem megjelenítésénél az SQL query-k száma (read) 1600 körül van, ami hihetetlenül magas (A DjDT is 3-4 perc alatt tölti be az adatokat). Egy termék megjelenítése 26 query-t igényel. Ez így nyilván kezelhetetlen.
A kérdésem az lenne, hogy mennyi lenne egy oldal betöltésénél az elfogadható SQL query-k (read) száma? Milyen tartományban kellene mozognia? Még a 500-at is irreálisan soknak tartanám, de érdekelne mások tapasztalata. (Termékek megjelenítése nélkül, egy "üres" oldal is 200 query körül van).
Az oldalnak nincs sok felhasználója (4-5), ám ők gyakran 10-15 oldalt is megnyitnak, és ez a mondjuk 60 oldal már néha nagyon komoly terhelést jelent, főleg hogy oldalanként 6 ajax kérés fut le percenként, egyenként kb. 40 query-vel, bár még ez a percenként ~14400 query nem olyan sok.
Köszi a tapasztalatok megosztását.
- 475 megtekintés
Hozzászólások
Gyanítom nem is egyszerűbb lekérdezések, hanem vaskos JOIN-ok. Pár hete egy fejlesztő nekem írt, hogy a 20GB-os adatbázison, a 4-5 INNER JOIN, 4-5 subselect, egy kis LIKE-kal leöntve, meg hasonló mókák olyan lassúak... azok.
Azt nézd meg, hogy nem nőtt-e meg valamelyik tábla extrém módon. Jellemzően az a probléma, hogy mondjuk néhány vagy ezer rekorddal az 5GHz-es NVMe SSD-s desktopon hasít, aztán a dualxeon már nem győzi (mert jó esetben van 3,5GHz turbóra, az NVMe szerver pedig nincs még minden bokorban).
- A hozzászóláshoz be kell jelentkezni
Nos, a termékekből (L) 1600 db van, ehhez van FK (LD néven), aminek a számozása most közel 59000-nél jár, és ezekhez az LD-khez vannak sorok (LDL, szintén FK, de LD-hez), amelyeknek a számozása pont most lépte át a 150.000-et.
Ez mostanában nőtt meg, míg februárban 20MB volt a tömörített dump mérete, ez most már 150MB, ami még mindig nem egy hatalmas mennyiség, de a fájlrendszeren - furcsa mód - az LD mérete 700 MB, az LDL mérete pedig mindössze 16MB .
Mennyire sok ez a szám? Egy L-hez 2 LD-nek kellene tartoznia, és azokhoz max. 10 LDL-nek darabonként, csak hát az emberek nem takarítanak maguk után. Mennyit javítana, ha ez ki lenne kényszerítve? Mennyire okoz a fenti méret lassulást, ha azokba a táblákba a query-k nem futnak bele? A cél a 10.000 L elérése év végére.
Amúgy ilyesmi query-k vannak:
SELECT
DISTINCT (62 paraméter neve vesszővel elválasztva)
FROM `eee_l` INNER JOIN `generalobj_gostatus` ON (`eee_l`.`way_to_eee_id` = `generalobj_gostatus`.`id`) WHERE (`generalobj_gostatus`.`code` = 'on_print' AND NOT (`eee_l`.`print_id` = '' AND `eee_l`.`print_id` IS NOT NULL) AND `eee_l`.`user_id` = 1 AND `eee_l`.`id` IN (1047, 1377, 1282, 83, 1303)) ORDER BY `eee_l`.`id` ASC
.
Találtam most egy olyan részt a kódban, ahol egy select (html) 32 eleméhez (option) mindig lefut egy sql query-s összehasonlítás. 20 terméknél ez már 640 plusz query, holott 20-ból, vagy kevesebből megoldható lenne... . Ezek azért hajmeresztőek.
- A hozzászóláshoz be kell jelentkezni
Elso korben pl a templateket lesd meg, mert ott kb a leggkonnyebb vegtelen sok queryt generalni. Ha teszemazt vegiglepdelsz egy 25 elemes listan egy forlooppal, majd ebben a listaban megprobalod elerni egy kapcsolt tabla 1 attributumat, akkor ez ebben az esetben legalabb 26 query lesz (ha 2-3 kapcsolt attributum kell, akkor ugye (3x25)+1). Itt pl reszelgetve egy kicsit a kodon (select_related/prefetch_related pl), le tudod tolni az egeszet 1 db queryre. Latatlanban nyilvan csak ilyen generikus, ismert dolgokat tud puffogtatni az ember.
- A hozzászóláshoz be kell jelentkezni
Most a 150.000 tabla sorszamat lecsokkentettem 50.000-re, es ez meg le fog menni 6-8000-ig, ami talan mar elfogadhato, de amit eszrevettem, hogy a tabla merete (fajlrendszeren) nem valtozott, meg most is 827 MB.
Mi tortenik pontosan akkor egy mysql adatbazisnal, ha torlunk egy rekordot? Ugy ertem magaban a binarisban. Onnan is el kellene tunnie a torolt sornak elvileg? Ennek kellene a meretben mutatkoznia ekkora mennyisegnel, nem?
Nyilván kellene egy flush, vagy optimize, de ami érdekes, hogy a készített zippelt dump mérete feleakkora lett.
- A hozzászóláshoz be kell jelentkezni
Ahogy én látni vélem semmilyen DB (vagy ISAM fájl, ahol van ilyen) nem ad vissza lemezhelyet az OS-nek, legfeljebb ha külön utasítást kap rá. A derék termék "belül" nyilvántartja a szabad és foglalt blokkokat, tehát ha rekordokat törölsz, egyes blokkok szabaddá válnak, de a fájlméret nem csökken.
- A hozzászóláshoz be kell jelentkezni
A dumpba a torolt dolgok nem kerulnek bele, de a DB-ben (adatbazistol fuggoen) ezek meg benne vannak, mert ki van optimalizalva egy csomo minden benne, es nem helytakarekossagra. PG-ben a vacuum szolgal erre, azt jobban ismerem. MySQL-nel fene tudja, reg hasznaltam.. gondolom attol is fugghet, hogy myisam vagy inno van belul.
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
OPTIMIZE TABLE tablanev;
Innodb+filepertable eseten ossze fog menni.
(kozben lesz egy cannot optimize, recreate warning ami normalis)
- A hozzászóláshoz be kell jelentkezni
Ha MySQL akkor ellenőrizd, hogy tutira InnoDB-e a táblatípus és hogy a file_per_table megy-e már. Ahogy írták előttem az OPTIMIZE TABLE húzza össze a táblákat a filernedszerben. A rekordszámból minden elfogadható, hogy ha elfogadod az adott query általi futásidőt. :) Jellemzően egy weboldalon nem fogadják el, hogy ha mondjuk 5 percig megy az adattárházba való lekérdezés.
EXPLAIN-nel nézd meg a konkrét lekérdezést, hogy mit szeretne csinálni, mennyire kezd el temp táblát generálni és mennyire használ indexeket. Ha a rekordszám sok, akkor a mezőtípusok megválasztásával érezhető hely szabadítható fel a táblákban és az indexekben is. Ezzel a result set is csökken valamelyest, bár egy LIMIT csodákra képes.
A MySQL oldalon mindentől függetlenül érdemes a mysqltuner.pl nevű történettel megnézni, hogy mit javasol. Rendre kéri a memória cache-ek és írási cache-ek jóval nagyobbra állítását. Ha ez a MariaDB féle leágazás, akkor a verziót érdemes megnézni.
Ami még előfordulhat, hogy ha naaaaagyon sok az "olyan" lekérdezés, akkor a query_cache kikapcsolása sokat segíthet. Ez teljesen a konkrét üzemtől függ. Van olyan szerverünk ami query_cache nélkül haldokolni és olyan, ami pedig a query_cache kikapcsolása után szárnyakat kapott.
- A hozzászóláshoz be kell jelentkezni
Ki mit tapasztalt, milyen tartományban mozog egy átlagos oldal betöltése sql lekérdezések tekintetében?
- A hozzászóláshoz be kell jelentkezni
Egy http request-nek normális esetben egy sql query-ből kellene összejönnie, de persze indokolt/bonyolultabb esetben lehet több (pl a kód felépítése miatt, amikor egyik modul nem tud a másikról, ezért magasabb szinten kell aggregálni az eredményt, nem lehet SQL szinten), de akkor is <10.
Persze egy oldal betöltéséhez kellhet több http request, de azért annak is hasonló nagyságrendben kellene mozognia.
Szóval ha egy oldalbetöltés ilyen sok SQL query-t eredményez, azzal valami nagy gond van.
- A hozzászóláshoz be kell jelentkezni
Egy http request-nek normális esetben egy sql query-ből kellene összejönnie, de persze indokolt/bonyolultabb esetben lehet több
Azért ez így elég erős, ez inkább a másik véglet :)
- A hozzászóláshoz be kell jelentkezni
online újság címlap. bonyolult szűrésekkel, stb. ha kikapcsoljuk a cache-t, akkor olyan 60.
aloldalakon ugyanígy 10 alatt
4 és fél éve csak vim-et használok. elsősorban azért, mert még nem jöttem rá, hogy kell kilépni belőle.
- A hozzászóláshoz be kell jelentkezni
A Djangohoz nem értek, de ez biztos nem normális
subscribe :)
- A hozzászóláshoz be kell jelentkezni
Érdemes átnézni a db-ben a táblákat, hogy a lekérdezésben használt mezőkre van-e index. (sok esetben elfelejtik létrehozni!) Továbbá érdemes view definiciokat hasznalni és azokra ereszteni a lekerdezest. Végül, mindenkepp érdemes az SQL query-ket átnézni, optimalizálni.
Másik oldalon a DB service optimalizálás, skálázást kellene megnezni, bufferek, cache mem máretek, stb.
Szijártó Zoltán
Aki tud az alkot, aki nem tud az csak szövegel.
- A hozzászóláshoz be kell jelentkezni
Első blikkre tipikusan az N+1 problémának tűnik.
Lásd:
https://medium.com/doctolib/understanding-and-fixing-n-1-query-30623109…
https://medium.com/@bretdoucette/n-1-queries-and-how-to-avoid-them-a12f…
- A hozzászóláshoz be kell jelentkezni
Loggold az összes queryt egy oldalon, meg azt is hogy honnan indulnak el. Valszeg azt fogod látni, hogy tök ugyanaz a query, vagy pár paraméter eltéréssel közel ugyanaz a query fut le rengetegszer. Aztán lehet a kódban matatni, pl. cache-elés, vagy hasonló query-k összevonása, vagy ilyesmi.
- A hozzászóláshoz be kell jelentkezni
Ez az egesz megoldhatatlannal tunik. Azt oldalt, plugint fejleszto kollegaval kellene egyutt dolgozni, ahol te csak devops feladatokat latsz el. Ezt at/ujrairni eleg melos lenne, tobb heg lehet mire atlatod. Az adatok gyomlalasa es nehany index segithet a dolgom, majd a mondat: "ez ilyen (lett)"
- A hozzászóláshoz be kell jelentkezni