Subqueries - goed idee?
----
Even een voorbeeldje en wat uitleg, om de nuttigheid te illustreren.
Stel, je hebt een tabel (klassement) met punten van voetbalploegen. 1 record per ploeg - 1 record bevat het totaal aantal punten van 1 ploeg.
En dan wil je uit de top 10 (bv. uit 24 ploegen in het totaal) willekeurig drie ploegen selecteren.
Mocht je een tabel hebben waarin de top 10 staat, al in volgorde, was het gemakkelijk:
Maar die tabel heb je uiteraard niet. Je hebt een tabel met 24 ploegen, niet in volgorde van punten.
Wat echter leuk is, is dat het resultaat van een select-query op zich ook een tabel is. Je kunt die ook gebruiken als subquery.
De tabel top_10_in_volgorde kunnen we zo vormen:
Samen maakt dat dus:
Code (php)
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
SELECT ploeg, punten
FROM
(SELECT ploeg, punten
FROM klassement
ORDER BY punten DESC
LIMIT 10) AS top_10_in_volgorde
ORDER BY RAND()
LIMIT 3
FROM
(SELECT ploeg, punten
FROM klassement
ORDER BY punten DESC
LIMIT 10) AS top_10_in_volgorde
ORDER BY RAND()
LIMIT 3
Simpel he.
----
Dus ja ... proberen te vermijden, of niet?
Graag geargumenteerd/gedocumenteerd.
Gewijzigd op 26/01/2012 17:21:08 door Kris Peeters
Wat je wél moet vermijden is ORDER BY RAND(). Dit is zeer inefficient, en kun je beter door PHP later doen.
Quote:
Je moet juist zoveel mogelijk subqueries gebruiken, dit verminderd het aantal keer dat je een aanvraag naar de database moet sturen.
Daar moet je wat genuanceerder in zijn en wat betreft het ORDER BY RAND() ook. Je geeft nu een verkeerd beeld af in mijn ogen.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
SELECT a.id
, b.naam
FROM (SELECT id
FROM flop) a
INNER JOIN (SELECT naam,ida
FROM flup) b
ON a.id = b.ida
SELECT a.id
, b.naam
FROM flop a
INNER JOIN flup b
ON a.id = b.ida
, b.naam
FROM (SELECT id
FROM flop) a
INNER JOIN (SELECT naam,ida
FROM flup) b
ON a.id = b.ida
SELECT a.id
, b.naam
FROM flop a
INNER JOIN flup b
ON a.id = b.ida
Jij suggeerd dus, dat de eerste query de gewenste is en dat je de tweede query maar beter achterwege kan laten. Vandaar dat ik schrijf dat je genuanceerde moet zijn, in de hoop dat je begrijpt waar het hier om draait.
En wat betreft het gegeven voorbeeld, zal ik als volgt aanpakken:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
create view toptienvw as
SELECT ploeg, punten
FROM klassement
ORDER BY punten DESC
LIMIT 10
create view randdrievantoptienfvw as
select ploeg
, punten
from toptienvw
order by
rand()
SELECT ploeg, punten
FROM klassement
ORDER BY punten DESC
LIMIT 10
create view randdrievantoptienfvw as
select ploeg
, punten
from toptienvw
order by
rand()
dan heb je ook nog iets aan de subquery, dat is dan 2 vliegen in 1 klap.
Het ligt er maar helemaal aan wat er al aan gegevens aanwezig is, en wat er dan eventueel nog opgehaald moet worden om tot het gewenste resultaat te komen.
Als je de toptienvw geggevens al hebt, dan heb je waarschijnlijk ook al de rand van 3, gezien de toegepaste script logica.
Als je de toptienvw gegevens niet nodig hebt maar alleen de rand 3 van toptienvw dan haal je die gegevens zo efficient mogelijk op.
Let wel: er is in feite niets tegen op subqueries mits deze goed sq slim geimplementeerd worden. En je past subqueries - zoals dit voorbeeld -:
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
SELECT ploeg, punten
FROM
(SELECT ploeg, punten
FROM klassement
ORDER BY punten DESC
LIMIT 10) AS top_10_in_volgorde
ORDER BY RAND()
LIMIT 3
pas toe als het echt niet anders kan, wat nu dus het geval is.
Is dit (zoals jacco al zegt) niet beter in php te doen? Dus de top tien ophalen met de query en dan daar een random op los te laten?
http://dev.mysql.com/doc/refman/5.0/en/explain.html
@Ger: Dubbel werk en dus per definitie niet beter. a) Je haalt teveel data op en b) dat ga je dan weer processen in een andere omgeving. Veel en soms heel erg veel data ophalen en processen in array's is de meest gemaakte ontwikkelfout in php. Over het algemeen komt dat door een gebrek aan SQL kennis en het performance kennis van MySQL. Subqueries zijn prima en kunnen volop toegepast worden. Heb je te maken met veel data (tienduizenden records) ga dan na hoe je query plan is en probeer dat te optimaliseren ipv te processen in php. Ontwerp indexen waar nodig en zorg dus altijd dat er indexed (unique) scans, index range scans zijn en zorg voor de juiste primairy en foreign keys zodat joins efficient afgehandeld worden! Al eens een query plan gechecked? Gewijzigd op 26/01/2012 20:09:36 door Aad B