Ik werk aan een Fotodatabase waar je op allerlei manieren je foto's kan indexeren. Nu heb ik vorige week een patch van iemand geimplementeerd en na wat testen kom ik erachter dat ik vanaf de zoekpagina de MySQL daemon zo goed als plat kan leggen. Het gaat om een query die automatisch gegenereerd wordt vanaf de zoekpagina. Het gaat fout als je zoekt op 2 velden uit dezelfde tabel. Omdat de applicatie op dit moment nog compatible moet zijn met MySQL 4.0 en ouder, kan ik geen subqueries gebruiken. Na wat debuggen ben ik er achter gekomen dat dit de query is waar hij op "stikt":
Ik heb dezelfde query direct in MySQL ingetikt en na een hele nacht was er nog geen output van de query. De reden dat er gebruik gemaakt wordt van "in (xxx)" en niet "=xxx" is dat er meerdere albums tegelijk opgevraagd kunnen worden, omdat albums ook andere albums kunnen bevatten.
Voorbeeldje
Als je nu in de webgui het album "Dieren" kiest, zal de query worden "in (1,2,3,4)".
Je kan echter ook kiezen voor, "Katten" OR "Honden". Dat zal een vergelijkbare query genereren als bovenstaande (behalve dat daar de keys 22 en 30 ipv 2 en 3 gebruikt worden).
Als je kiest voor "Katten" AND "Honden" (dus foto's die zowel in het album katten als in het album honden staan) dan wordt deze query gegenereerd (dezelfde dus, alleen OR -> AND):
Deze query werkt wel en is ook binnen een seconde klaar.
Nu kan ik natuurlijk de code herschrijven dat bovenstaande query veranderd wordt in "in (22, 30)"; die heb ik via de MySQL CLI geprobeerd en dat werkt; echter, ik zou toch graag willen weten waarom deze query niet werkt... dat hij minder efficient is dat "in (22, 30)" begrijp ik, waarom hij helemaal niet werkt (of heel erg lang duurt om uit te voeren) niet.
Het liefste wil ik de query zo houden, omdat de code die deze query genereerd voor de AND er toch in moet blijven, omdat ik zonder subqueries dat eigenlijk niet anders op kan lossen.
Tenslotte nog de explain van de eerste query:
Update:
Nog even wat testen gedaan... als ik "in (xxx)" vervang door "=xxx" heb ik hetzelfde probleem.
Update2:
Weer wat aan het testen geweest... als ik de query als volgt opschrijf:
werkt het wel. Terwijl dat volgens mij dezelfde query zou moeten zijn... iemand die dat kan bevestigen of weerleggen?
Hij werkt ook als ik de laatste regel verander in
De explain van deze query is trouwens behoorlijk verschillend van de oorspronkelijke
Maak ik nou een fout of loop ik tegen een bug in de optimizer aan?
SQL:
1
2
3
4
5
6
7
8
| select count(distinct ph.photo_id) from zoph_photos as ph, zoph_photo_albums as pa0, zoph_photo_albums as pa1 where (pa0.album_id in (30) and pa0.photo_id = ph.photo_id) or (pa1.album_id in (22) and pa1.photo_id = ph.photo_id); |
Ik heb dezelfde query direct in MySQL ingetikt en na een hele nacht was er nog geen output van de query. De reden dat er gebruik gemaakt wordt van "in (xxx)" en niet "=xxx" is dat er meerdere albums tegelijk opgevraagd kunnen worden, omdat albums ook andere albums kunnen bevatten.
Voorbeeldje
code:
1
2
3
4
5
6
7
8
| Albums
Dieren (1)
Katten (2)
Honden (3)
Vissen (4)
Auto's (5)
Volvo (6)
Peugeot (7) |
Als je nu in de webgui het album "Dieren" kiest, zal de query worden "in (1,2,3,4)".
Je kan echter ook kiezen voor, "Katten" OR "Honden". Dat zal een vergelijkbare query genereren als bovenstaande (behalve dat daar de keys 22 en 30 ipv 2 en 3 gebruikt worden).
Als je kiest voor "Katten" AND "Honden" (dus foto's die zowel in het album katten als in het album honden staan) dan wordt deze query gegenereerd (dezelfde dus, alleen OR -> AND):
SQL:
1
2
3
4
5
6
7
8
| select count(distinct ph.photo_id) from zoph_photos as ph, zoph_photo_albums as pa0, zoph_photo_albums as pa1 where (pa0.album_id in (30) and pa0.photo_id = ph.photo_id) and (pa1.album_id in (22) and pa1.photo_id = ph.photo_id); |
Deze query werkt wel en is ook binnen een seconde klaar.
Nu kan ik natuurlijk de code herschrijven dat bovenstaande query veranderd wordt in "in (22, 30)"; die heb ik via de MySQL CLI geprobeerd en dat werkt; echter, ik zou toch graag willen weten waarom deze query niet werkt... dat hij minder efficient is dat "in (22, 30)" begrijp ik, waarom hij helemaal niet werkt (of heel erg lang duurt om uit te voeren) niet.
Het liefste wil ik de query zo houden, omdat de code die deze query genereerd voor de AND er toch in moet blijven, omdat ik zonder subqueries dat eigenlijk niet anders op kan lossen.
Tenslotte nog de explain van de eerste query:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
| mysql> explain select count(distinct ph.photo_id) from zoph_photos as ph, zoph_photo_albums as pa0, zoph_photo_albums as pa1 where (pa0.album_id in (30) and pa0.photo_id = ph.photo_id) or (pa1.album_id in (22) and pa1.photo_id = ph.photo_id); +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ | 1 | SIMPLE | ph | index | PRIMARY | PRIMARY | 4 | NULL | 4627 | Using index | | 1 | SIMPLE | pa0 | index | PRIMARY | PRIMARY | 8 | NULL | 4777 | Using index | | 1 | SIMPLE | pa1 | index | PRIMARY | PRIMARY | 8 | NULL | 4777 | Using where; Using index | +----+-------------+-------+-------+---------------+---------+---------+------+------+--------------------------+ 3 rows in set (0.02 sec) |
Update:
Nog even wat testen gedaan... als ik "in (xxx)" vervang door "=xxx" heb ik hetzelfde probleem.
Update2:
Weer wat aan het testen geweest... als ik de query als volgt opschrijf:
SQL:
1
2
3
4
| select count(distinct ph.photo_id) from zoph_photos as ph join zoph_photo_albums as pa0 on pa0.photo_id=ph.photo_id join zoph_photo_albums as pa1 on pa1.photo_id=ph.photo_id where pa0.album_id=30 or pa1.album_id=22; |
werkt het wel. Terwijl dat volgens mij dezelfde query zou moeten zijn... iemand die dat kan bevestigen of weerleggen?
Hij werkt ook als ik de laatste regel verander in
SQL:
1
| where pa0.album_id in (30) or pa1.album_id in (22); |
De explain van deze query is trouwens behoorlijk verschillend van de oorspronkelijke
SQL:
1
2
3
4
5
6
7
8
| mysql> explain select count(distinct ph.photo_id) from zoph_photos as ph join zoph_photo_albums as pa0 on pa0.photo_id=ph.photo_id join zoph_photo_albums as pa1 on pa1.photo_id=ph.photo_id where pa0.album_id in (30) or pa1.album_id in (22); +----+-------------+-------+--------+---------------+---------+---------+----------------------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+--------+---------------+---------+---------+----------------------+------+--------------------------+ | 1 | SIMPLE | pa0 | index | PRIMARY | PRIMARY | 8 | NULL | 4777 | Using index | | 1 | SIMPLE | ph | eq_ref | PRIMARY | PRIMARY | 4 | zophdev.pa0.photo_id | 1 | Using index | | 1 | SIMPLE | pa1 | ref | PRIMARY | PRIMARY | 4 | zophdev.ph.photo_id | 47 | Using where; Using index | +----+-------------+-------+--------+---------------+---------+---------+----------------------+------+--------------------------+ |
Maak ik nou een fout of loop ik tegen een bug in de optimizer aan?
[ Voor 26% gewijzigd door Verwijderd op 19-01-2006 21:06 ]