Avatar billede razmuz_dk Nybegynder
24. august 2006 - 16:35 Der er 5 kommentarer og
1 løsning

Overdrevet hastighedsreduktion ved brug af IN i et JOIN?

Hej eksperter,

Følgende sql-kald henter de 5 seneste topics i de fora, som $user_id har valgt som favorit-fora:

SELECT
    ft.title,
    ft.views,
    ft.replies,
    f.forum_id,
    f.title forum_title
FROM forum_topics ft
JOIN forums f ON f.forum_id IN (SELECT forum_id FROM forum_favorites WHERE user_id = '".$user_id."')
JOIN forum_posts fp ON ft.last_post_id = fp.post_id
WHERE ft.type = '0'
ORDER BY ft.last_post_id
LIMIT 5

Det kald bliver udført på 0,33 sekunder - for langsomt!

Jeg har undersøgt sub-queryen og den returnerer 3 forum_id'er. Hvis jeg erstatter ovenstående query med denne query:

SELECT
    ft.title,
    ft.views,
    ft.replies,
    f.forum_id,
    f.title forum_title
FROM forum_topics ft
JOIN forums f ON f.forum_id = 'X'
JOIN forum_posts fp ON ft.last_post_id = fp.post_id
WHERE ft.type = '0'
ORDER BY ft.last_post_id
LIMIT 5

hvor X er ét af de tre fora som $user_id har som favorit - så køres hver af disse på ~0,00 sekunder. Man skulle tro af summen af de tre kald skulle være lig eksvekveringstiden på det oprindelig kald med IN()... eller hvad?

Ved at bruge explain på det oprindelig kald med IN kan jeg se at der ingen indexes bruges til tabellerne forum og forum_topics - og det er selve den ORDER BY ft.last_post_id der er skyld i forespørgslen tager lang tid, fordi den af en eller anden grund ikke kan bruge indexet på den kolonne. Jeg har uden held forsøgt med FORCE INDEX(). Faktisk skriver EXPLAIN på den oprindelige forespørgsel NULL i possible_keys på både forums og forum_topics... selvom den naturligvis findes nogle keys/indexes.

Jeg kører en MySQL 4.1.15-Debian_1-log hvis det skulle have interesse.

Håber ik' min forklaring blev for indviklet.

På forhånd tak! :-)
Avatar billede razmuz_dk Nybegynder
24. august 2006 - 16:36 #1
... og sub-forespørgslen er IKKE skyld i den kører langsomt, da denne også udføres på ~0,01 sekunder.
Avatar billede razmuz_dk Nybegynder
24. august 2006 - 16:40 #2
... ups jeg manglede lige en AND ft.forum_id = f.forum_id på det ene JOIN - men efter at have testet med dette kan jeg stadig ikke finde forklaringen på hvorfor kaldet med IN() er så meget langsommere.
Avatar billede kjulius Novice
24. august 2006 - 19:10 #3
Hvad hvis du nu omskriver den til ikke at benytte en subquery. Måske kan den så bedre udnytte de indexes der er oprettet...
Jeg tror den skal se nogenlunde sådan her ud:


SELECT
    ft.title,
    ft.views,
    ft.replies,
    f.forum_id,
    f.title forum_title
FROM forum_topics ft
CROSS JOIN forum_favorites ff
INNER JOIN forums f ON f.forum_id = ff.forum_id
INNER JOIN forum_posts fp ON ft.last_post_id = fp.post_id
WHERE ft.type = '0' AND  ff.user_id = '".$user_id."'
ORDER BY ft.last_post_id
LIMIT 5
Avatar billede coderdk Praktikant
25. august 2006 - 02:19 #4
Hvordan ser query planen ud?
Avatar billede razmuz_dk Nybegynder
25. august 2006 - 08:43 #5
Kjulius - det hjalp :-)

Lige nu undrer jeg mig bare over hvorfor jeg egentlig ville have den subquery med i første omgang. Men så er det jo godt I kan hjælpe mig :-)

Umiddelbart bryder jeg mig ikke om cross-join'ens syntax. Jeg synes det er mere logisk at have hvert eneste joins "join-clause" i den efterfølgende ON... ellers synes jeg WHERE'en nemt kan blive meget rodet :-) Så jeg har tilladet mig at omskrive dit kald (hvis nogen sku ha interesse) til dette:

SELECT
    ft.title,
    ft.views,
    ft.replies,
    f.forum_id,
    f.title forum_title
FROM forum_topics ft
JOIN forum_favorites ff ON ff.user_id = '278'
JOIN forums f ON f.forum_id = ff.forum_id
JOIN forum_posts fp ON ft.last_post_id = fp.post_id
WHERE ft.type = '0'
ORDER BY ft.last_post_id
LIMIT 5

Men smid et svar :-)
Avatar billede kjulius Novice
25. august 2006 - 10:53 #6
Smag og behag er heldigvis forskellig. :-)
Bare det er effektivt, betyder formen jo mindre...
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester