Avatar billede gyxi Nybegynder
14. juni 2008 - 14:19 Der er 4 kommentarer og
1 løsning

Bedre performance på enormt mange mange-til-mange

Jeg har 3 tabeller som er forbundet med en mange-til-mange relation:

- Posts
- Categories
- Categorizations

Categorizations er en mange-til-mange tabel mellem Posts og Categories. Min opgave er at finde Posts som er medlem af nogle bestemte Categories. Jeg har fået hjælp af bl.a. arne_v (tak) til at gøre det sådan:

SELECT COUNT(DISTINCT p1.id) AS count
FROM posts p1
    INNER JOIN categorizations pc1 ON p1.id = pc1.postid
    INNER JOIN categories c1 ON pc1.categoryid = c1.id
    INNER JOIN posts p2 ON p1.id = p2.id
    INNER JOIN categorizations pc2 ON p2.id = pc2.postid
    INNER JOIN categories c2 ON pc2.categoryid = c2.id
WHERE (pc1.categoryid = 735) AND (pc2.categoryid = 1187)

Det fungerer rigtig fint, men problemet opstår når jeg prøver med flere end to kategorier. F.eks. 5, hvilket ser sådan ud:

SELECT distinct p1.Id, p1.Title, p1.Text, p1.UserId, p1.VoteCount,
        p1.ContentType, p1.IsHardcore, p1.SourceUrl, p1.Alias, p1.CommentCount,
        p1.SubmittedTime, p1.RecentVoteCount, p1.PrimaryImageUrl
FROM    Posts p1
INNER JOIN categorizations pc1 ON p1.Id = pc1.PostId
INNER JOIN posts p2 ON p1.id = p2.id
INNER JOIN categorizations pc2 ON p2.Id = pc2.PostId
INNER JOIN posts p3 ON p2.id = p3.id
INNER JOIN categorizations pc3 ON p3.Id = pc3.PostId
INNER JOIN posts p4 ON p3.id = p4.id
INNER JOIN categorizations pc4 ON p4.Id = pc4.PostId
INNER JOIN posts p5 ON p4.id = p5.id
INNER JOIN categorizations pc5 ON p5.Id = pc5.PostId
WHERE ( (pc1.CategoryId = 1256)
OR  (pc2.CategoryId = 770)
OR  (pc3.CategoryId = 677)
OR  (pc4.CategoryId = 1262)
OR  (pc5.CategoryId = 937) )
ORDER BY p1.SubmittedTime DESC

Det kald tager 20 sekunder, selvom der ikke er mange data - og det lader til at tage eksponentielt længere tid for hver ekstra kategori som tilføjes. Hvis jeg bruger AND i stedet for OR, svarer den næsten med det samme.

Nogle forslag til hvordan jeg kan opnå rimelig ydelse for et kald hvor jeg vil hente alle Posts som er medlem af én eller flere kategorier?
Avatar billede erikjacobsen Ekspert
14. juni 2008 - 14:35 #1
Du skal vel ikke udvide antallet af joins, hvis jeg forstår dig rigtigt:

SELECT COUNT(DISTINCT p1.id) AS count
FROM posts p1
    INNER JOIN categorizations pc1 ON p1.id = pc1.postid
    INNER JOIN categories c1 ON pc1.categoryid = c1.id
WHERE (pc1.categoryid = 735) OR (pc1.categoryid = 1187)

Skal du have 5, så tilføjer du bare i WHERE-delen. Måske. Måske kan du nøjes med een JOIN ... men jeg ved jo heller ikke hvad du vil.
Avatar billede gyxi Nybegynder
14. juni 2008 - 14:50 #2
Nåh ja, for OR behøver jeg vel kun ét eneste join! Den anden manøvre var jo netop for at understøtte AND ... (prøver lige)
Avatar billede gyxi Nybegynder
14. juni 2008 - 14:52 #3
Ja så er der fart på. Tak for dit klarsyn. Læg svar.
Avatar billede erikjacobsen Ekspert
14. juni 2008 - 14:56 #4
Jeg samler slet ikke på point, tak. Svar selv, og accepter dit eget svar.
Avatar billede gyxi Nybegynder
14. juni 2008 - 15:19 #5
det gør jeg heller ikke, det er jo også bare et redskab til at synliggøre hvem der fik 'æren' af at have løst en andens problem :)
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



IT-JOB

De Nationale Geologiske Undersøgelser for Danmark og Grønland (GEUS)

IT-systemadministrator søges til GEUS

Udviklings- og Forenklingsstyrelsen

Kontorchef med ansvar for tværgående service management

RISMA Systems A/S

Senior PHP-udvikler