PDA

Pogčedajte punu verziju : [MySQL] Optimizacija upita, indexi


mb_sa
13. 08. 2009., 12:18
Pozdrav.

http://rapidshare.com/files/266873156/testdev.sql.zip.html

Sa linka iznad mozete skinuti SQL fajl sa bazom i 3 tabele (njihova struktura i testni podaci).

Dakle, 3 tabele u kojima se čuvaju informacje o vijestima, kategorijama i autorima. Princip news sistema.

Napisao sam upit koji ispisuje 5 vijesti iz odredjene kategorija koja ima svoje potkategorije. Vijesti su soritrane po pozijama i vremenu objave ukoliko ne bude dovoljno vijesti kojima su označene pozicije, jer upit treba da vrati uvijek 5 redova.

Upit je ispod.

SELECT v.id, v.naslov, a.ime_prezime, v.mala_slika, v.uvod
FROM vijesti v, kategorije k, administratori a
WHERE k.kategorija_id = v.kategorija
AND v.autor = a.id
AND v.tip =1
AND v.media =0
AND v.pozicija
IN (
'5', '6', '7', '8', '9', '1000'
)
AND k.parent_id
IN ( 4, 5 )
AND v.id NOT
IN ( 22083, 22075, 22077, 22070 )
AND v.datum_objave <= '2009-08-13 10:58:00'
ORDER BY v.pozicija, v.datum_objave DESC
LIMIT 5

// ako je pozicija 1000, to znači da nema pozicije

Na bazu od 20.000 reedova upit se izvrsava u prosjeku nekih 0.3s sto mi je puno jer ovakih upita imam oko 10-tak na naslovnici (razlciite pozicije (v.pozicija) i kategorija (k.parent_id)).

EXPLAIN upita vraca: http://www.imagesforme.com/show.php/636527_explain.jpg

Ja sam stavio odredjne indexe (vidjećete kada ako pogledate sturkturu tabela iz priloga) koje MySQL i korsiti, tako da je kolona Rows u EXPLAIN tabele sasvim OK. Problem je očigledno kod onog što je napisano u EXTRA koloni.

Mislim da bi se ovaj upit trebao brze zvrsavati, no za to mi je potrebna vasa pomoć? Imate li prijedloga kako da podesim indexe?

Nadam se da nisam nista propustio spomenuti.

Hvala unaprijed.

DejanVesic
13. 08. 2009., 14:42
Kandidati za indeks su: (tim redom):

- vesti.kategorija
- vesti.datum_objave
- vesti.pozicija

pa dodaj jedan po jedan, testiraj i vidi da li se nešto menja.

mb_sa
13. 08. 2009., 17:28
@DejanVesic

EXPLAIN vraca iste rezultate. Vrijeme izvrsavanja takodjer isto.

Ne znam da li si zapazio ali kolona 'pozicija' je pobrojani tip (ENUM) i negdje sam pročitao da za njih nije potrebno stavljati indexe, a takodjer ona sadrzai vrijenodsti od 1-16, te 1000, od cega je 99,99 posto vrijednost 1000, nije li i to premala kardinalost? Ispravi me ako grijesim? Hvala.

------

I dalje imam prolbem, ali primjetio sam da su bolja vremena izvrsavanja bez ijednog indexa. U tom slucaju nema kreiranja temp tabele (Using temporary).

lijep pozdrav.

DejanVesic
13. 08. 2009., 18:51
Nisam MySQL ekspert, ali recimo na Oracle / SQL sistemima se indeksi vrlo često ne koriste ako je kardinalnost tabela ispod nekog limita - prosto je jednostavnije učitati celu tabelu u memoriju no juriti po b-stablima od indeksa. Zato i stoji da za jako male skupove indeks i ne treba.

Što se tiče enuma - moguće je da se pravi implicitni indeks (ali ovo debelo treba proveriti dokumentaciju). U suštini, ako je rezultujući set pre primene tog uslova dovoljno mali, onda će se filtriranje po poziciji raditi prostim upoređivanjem (indeks ne treba).

Ako je veliki, onda definitivno treba da postoji neki način da nađe slogove koji zadovoljavaju uslov.

Za veliku količinu podataka neki od indeksa će definitivno pomoći.

mb_sa
14. 08. 2009., 11:10
Hvala na odgovoru.

U MySQL dokumentaciji pise da neće korstiti index za order by ako se mixaju ASC i DESC, mada sam ja stavljao ORDER BY v.pozicija DESC, v.datum_objave DESC, ali opet ista situacija.

Nisam pametan :)

jablan
14. 08. 2009., 14:53
Nemam mysql da probam, ali me živo zanima da li se menja execution plan ako se upit napiše pomoću JOIN-ova:
SELECT v.id, v.naslov, a.ime_prezime, v.mala_slika, v.uvod
FROM vijesti v
left join kategorije k on k.kategorija_id = v.kategorija
left join administratori a v.autor = a.id
WHERE
v.tip =1
AND v.media =0
AND v.pozicija
IN (
'5', '6', '7', '8', '9', '1000'
)
AND k.parent_id
IN ( 4, 5 )
AND v.id NOT
IN ( 22083, 22075, 22077, 22070 )
AND v.datum_objave <= '2009-08-13 10:58:00'
ORDER BY v.pozicija, v.datum_objave DESC
LIMIT 5

BTW, možeš li da keširaš rezultate?

mb_sa
14. 08. 2009., 15:38
Nemam mysql da probam, ali me živo zanima da li se menja execution plan ako se upit napiše pomoću JOIN-ova:
SELECT v.id, v.naslov, a.ime_prezime, v.mala_slika, v.uvod
FROM vijesti v
left join kategorije k on k.kategorija_id = v.kategorija
left join administratori a v.autor = a.id
WHERE
v.tip =1
AND v.media =0
AND v.pozicija
IN (
'5', '6', '7', '8', '9', '1000'
)
AND k.parent_id
IN ( 4, 5 )
AND v.id NOT
IN ( 22083, 22075, 22077, 22070 )
AND v.datum_objave <= '2009-08-13 10:58:00'
ORDER BY v.pozicija, v.datum_objave DESC
LIMIT 5

BTW, možeš li da keširaš rezultate?

Nažalost ne mijenja nista.

I mysql ih sam cache-ira, ali sto znate nakon update nad tabelom, cache je uništen.

Planirao sam da neke cache-iram preko PAER cache-lite (lifetime bi mogao da bude 5 minuta), ali ne mogu ih sve.

miks
14. 08. 2009., 15:54
Probaj da stavis index na kategorije u redosledu (parent_id, kategorija_id)

mb_sa
14. 08. 2009., 19:45
Probaj da stavis index na kategorije u redosledu (parent_id, kategorija_id)

Ne pomaze.

Pozdrav.

degojs
15. 08. 2009., 01:43
A kolika je ta tvoja baza? Možda je suviše mala trenutno da bi bilo neke razlike?

bOkIcA
15. 08. 2009., 03:28
Ne razumem se kompletno ali sumnjam na to da sortiranje te kolicine podataka (20000+) uzima vecinu vremena. To pokazuje i "explain" gde se vidi da se koristi temp tabela pa tkzv filesort jer je verovatno previse materijala za direktnu obradu u memoriji.

Neki predlog moze biti da mozda arhiviras vesti pa da takve upite radis na manjim tj samo aktuelnim podacima ili sl.

srdjevic
15. 08. 2009., 09:48
Probaj ovo:
ALTER TABLE vijesti ADD INDEX `sortindex` (`pozicija`, `datum_objave`);

Onda u upitu u odeljku FROM umesto "vijesti v," stavi "vijesti v FORCE INDEX (sortindex),"

Pravi ti temp tabelu zbog sortiranja, a ne uslova.... ;)

Edit: i daj screenshot explain-a sa ovim cak i ako ne radi brze (osim ako je identican onom iz prve poruke)

mb_sa
16. 08. 2009., 09:46
@degojs

Baza ima preko 20.000 redova, mislim da bi trebalo biti dovljno.

@bOkIcA

Arhiviranje mi trenutno nije opcija. To je planirano, ali nakon odredjenog vremena, gdje bi baza tada imala duplo i vise redova

@srdjevic

http://www.imagesforme.com/show.php/640038_explain2.jpg

Kada odradim FORCE indexa, mysql ga i koristi. Explain daje nesto bolje rezultate, ali pomaka sa brzinom nema. Upit je izgleda najbrzi kada nema ni jednog indexa.


Hvala na dosadasnjoj pomoci.

ivanhoe
16. 08. 2009., 22:28
ako nema pomaka sa brzinom, a koristi index za sortiranje (ne pojavljuje ti se filesort), onda je mozda problem u podesavanju servera, da ne moze da stavi ceo index u memoriju jer mu je dodeljena velicina cache-a premala. Jel baza InnoDB ili MyISAM ili nesto trece?

srdjevic
17. 08. 2009., 18:19
Pa da, sad ne koristi temp table, samo filesort... bice da je premali kes... mislim da bi sa vecim kesom ovako radilo bolje od pocetnog.

mb_sa
30. 08. 2009., 16:47
U MySQL dokumentaciji pise da neće korstiti index za order by ako se mixaju ASC i DESC, mada sam ja stavljao ORDER BY v.pozicija DESC, v.datum_objave DESC, ali opet ista situacija.

Nisam pametan :)

Evo da javim sta se je desilo, vjerujm da ce i drugima biti od pomoci.

Povecanje sort i key buffera je pomoglo, ali problem ovog upita je bio "ORDER by pozicija, datum_objave DESC".

Dakle, mysql ne zna da korsiti index ukoliko miksamo ASC i DESC, što je bio kod mene slučaj. Promjena upita na ORDER by pozicija DESC, datum_objave DESC uz kreiran index (pozicija,datum) jer radila dalekoooo brze (reda 0.0010s).

Mejdutim, prolbem je sto vo ne vraca željene rezultate. U tabelu sam dodao pozicija_reverse koja je sadrzava suprotne vrijednosti, tako da sam mogao da sortiram po principu pozicjija DESC, datum_obajve DESC. Naravno kreiran je index za (pozicija_reverse,datum_obajve) i upit se izvrsava za 0.0010.

Povecanje key buffer size sort buffer size je pomoglo da korsiti index (pozicija,datum) tako da je pomoglo i kod ovog upita i generlano kod upita koji su imali samo sortiranje po datumu.

Hvala na pomoci i usescu!