[MySQL] Performance Joins met OR conditie (indexing)

Pagina: 1
Acties:

  • Quartje
  • Registratie: Oktober 2000
  • Laatst online: 13-05 12:58
Ik heb een vrij uitgebreide query onder andere bestaande uit 14 left joins. De query doet er ongeveer 4 seconden over, waarbij het resultaat ongeveer uit 2500 records bestaat. Dit is op zich redelijk acceptabel voor mijn geval.

Echter een LEFT JOIN gooit roet in het eten. Hierbij wordt een tabel op twee andere tabellen gejoined. Deze join levert de correcte resultaten op met een OR-conditie, alleen doet de totale query er dan ongeveer 30 seconden over. Wanneer ik hier 'voor de gein' AND van maak duurt de query dus slechts 4 seconden (maar levert uiteraard de verkeerde resultaten op).

Dit heeft o.a. te maken met de index. Bij een AND conditie wordt er wel gebruik gemaakt van de vastgelegde indices en bij OR heeft MySQL daar geen profijt van. Hoe zou ik dit probleem kunnen tackelen?

Voor de duidelijkheid het relevante deel van de query:

code:
1
2
3
4
5
...
LEFT JOIN tblProgramProductBid progprodbid
ON (progprodbid.ProgramProductId = progprods.ProgramProductId OR
tblLastSubProgramBid.SubProgramCompanyBidId = progprodbid.SubProgramCompanyBidId)
...

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:34
Dit gaat helemaal mislopen; je zult imo een cartesiaans product krijgen. Vandaar dat je query er zo lang over doet. (Check je resultset maar, er zullen verkeerde data in zitten).

Trouwens, een query met 14 left joins?? Dit roept bij mij nogal een aantal vraagtekens op. Waarom heb je 14 left joins nodig? Een query met 14 joins vind ik zowiezo nogal vaag...

Als je wilt joinen op veld 1 of op veld2, dan zal je dat niet in je JOIN conditie kwijt kunnen, maar zal je nog eens op dezelfde tabel moeten joinen (met idd een left join).

https://fgheysels.github.io/


Verwijderd

Beetje blinde gok maar je kan de Left join splitsen in twee left joins en een union. Afhankelijk van wat het probleem is zou dit effectiever kunnen zijn maar net zo goed nog een stuk trager.

Dus iets als
code:
1
2
3
4
5
6
7
8
9
......
LEFT JOIN tblProgramProductBid progprodbid
ON (progprodbid.ProgramProductId = progprods.ProgramProductId)
......
UNION 
......
LEFT JOIN tblProgramProductBid progprodbid
ON (tblLastSubProgramBid.SubProgramCompanyBidId = progprodbid.SubProgramCompanyBidId)
...


Maar outer joins zijn per definitie nogal traag en dat een AND wél snel is zegt op zich niets over de snelheid van een join met een OR. De verzameling records die aan de AND eis voldoet kan gewoon een stuk kleiner zijn dan de verzameling records die aan de OR eis voldoet.

[ Voor 3% gewijzigd door Verwijderd op 09-12-2004 10:10 ]


  • Dido
  • Registratie: Maart 2002
  • Laatst online: 13:57

Dido

heforshe

Als ik het goed heb probeer je het volgende:

Je hebt het eerste stuk van je query (resultset A)

daaraan wil je koppel alles uit tabellen B en C onder de volgende voorwaarden:

C hoort bij A
OF
B hoort bij C

Je realiseert je dat je in dat laatste geval alle samenhorende records uit B en C terugkrijgt, zonder dat die iets te maken hebben met A? En dat voor ieder record uit A!
Ik denk dat je eerst eens precies (vooral ook voor jezelf) onder woorden moet brenegn wat je wilt, want het lijkt me stug dat je, zoals whoami zegt, een cartesiaans product wilt hebben.

Wat betekent mijn avatar?


  • Quartje
  • Registratie: Oktober 2000
  • Laatst online: 13-05 12:58
Ok, er is dus nog wat verwarring over wat ik precies wil. Hieronder staat uit gedeelte uit het db-relatieschema:

Afbeeldingslocatie: http://home.student.utwente.nl/r.h.m.hakvoort/subquery/dbrelations.gif


tblProgramProductBid moet altijd gejoined worden op het ProgramProductId van tblProgramProduct.
Echter er bestaat niet altijd een bijbehorend record in tblSubProgramBid.TblProgramProductBid mag dan alleen maar gejoined worden als deze bestaat (tblProgramProductBid.SubProgramCompanyBidId is dan NIET NULL). Misschien dat het zo ietsje duidelijker wordt? Dit kan je dan toch alleen maar bereiken door een OR conditie? Relatie A in het plaatje bestaat altijd, terwijl relatie B niet hoeft te bestaan in bepaalde gevallen.

[ Voor 9% gewijzigd door Quartje op 09-12-2004 10:41 ]


  • Dido
  • Registratie: Maart 2002
  • Laatst online: 13:57

Dido

heforshe

Als relatie b niet bestaat wil je wel de records uit relatie a hebben?
code:
1
2
(tabel1 JOIN        tabel2 ON tabel1.id = tabel2.id) 
        LEFT JOIN   tabel3 ON tabel2.id = tabel3.id

zoiets?
Volgens mij krijg je nu alle records uit de tabel1/tabel2 relatie, en als ie bestaat ook het gerelateerde record uit tabel3. Klinkt als wat je wilt?

[ Voor 31% gewijzigd door Dido op 09-12-2004 10:59 ]

Wat betekent mijn avatar?


Verwijderd

tblProgramProductBid moet altijd gejoined worden op het ProgramProductId van tblProgramProduct.
(Dit is regel 2 hieronder)
Echter er bestaat niet altijd een bijbehorend record in tblSubProgramBid.
TblProgramProductBid mag dan alleen maar gejoined worden als deze bestaat (tblProgramProductBid.SubProgramCompanyBidId is dan NIET NULL).
(En dit regel 3)


Dus zoiets (gewoon een inner join)
code:
1
2
3
Select * 
from tblProgramProduct join tblProgramProduct ON(tblProgramProduct.ProgramProductID=tblProgramProductBid.ProgramProductID)
WHERE (tblProgramProductBid.SubProgramCompanyBidId is NOT NULL)

[ Voor 6% gewijzigd door Verwijderd op 09-12-2004 11:23 ]

Pagina: 1