Python Django - DjDT - elfogadhato SQL query-k szama

Fórumok

Ü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.

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).

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.

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. 

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.

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 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?

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.

Ki mit tapasztalt, milyen tartományban mozog egy átlagos oldal betöltése sql lekérdezések tekintetében?

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 Djangohoz nem értek, de ez biztos nem normális 

subscribe :)

Szerkesztve: 2021. 08. 11., sze – 14:32

 

É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.

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.

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)"