Query controleer item en categorie koppelingen langzaam

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Dan Me

Dan Me

25/01/2011 22:33:37
Quote Anchor link
Eey mensen,

Heb even jullie hulp nodig bij het volgende:

Ten eerste, onderstaande situatie is fictie wat de data betreft. Heb even een "auto" als onderwerp genomen om het makkelijker te begrijpen.

Mijn tabellen:

CAR (ID, NAME)
CATEGORY (ID, PARENT_ID, NAME)
CAR_IN_CATEGORY (ID, CAR_ID, CATEGORY_ID)

Situatie:

Een auto kan aan 1 of meerdere categorieën gekoppeld zijn op welke niveau dan ook.
Het systeem gaat middels een stappen proces door de categorieën. Bij elke stap (categorie boom) moet ik controleren welke categorieen ik nog moet laten zien. Alleen degene welke daaronder nog een auto gekoppeld hebben. Bijv.

2 snelle[=categorie], rode[=categorie], luxe[=categorie] auto's
0 snelle[=categorie], gele[=categorie], luxe[=categorie] auto's

De gele auto hoef ik dus niet te laten zien. Nu heb ik de volgende query om per categorie weergave te controleren of er auto's onder hangen. Ik moet dus alle auto's hebben die gekoppeld zijn aan meerdere geselecteerde categorieën. Een AND verhaal dus, niet een OR.

Huidige QUERY:

SELECT car.id
FROM car_in_category cc
JOIN car c ON car.id = cc.car_id
WHERE cc.category_id IN (119456,119458,119460,119462,119464,119738)
GROUP BY car.id
HAVING COUNT(*) = 6;

119456,119458,119460,119462,119464,119738 <= dit zijn dus de geselecteerde categorieën.

Probleem:

Ik heb op dit moment 60.000 auto's in mijn database welke allen gelinkt zijn aan 1 of meerdere categorieën. Als ik bovenstaande query uitvoer ben ik binnen deze situatie 0.5 tot 1.4 sec bezig. Als ik dat voor 10 categorieën wil doen op een pagina is dat uiteraard niet acceptabel.

Iemand een idee waaraan dit kan liggen of hoe het beter zou kunnen?

Ik heb indexes op alle waardes staan welke gebruikt worden.
Dat is dan ook geen rocket-science. Dus daar ligt het dan toch ook niet aan?

car.id PK
category.id PK
car_in_category.car_id FK
car_in_category.category_id FK

Anyone?

Thanks!
 
PHP hulp

PHP hulp

22/12/2024 11:01:58
 
Aad B

Aad B

25/01/2011 23:18:17
Quote Anchor link
Vreemd datamodel en waarom is de having?
Vreemd is dat rood/snel/luxe allen een categorie zijn.
Het lijkt mij dat je datamodel een beetje te ver is uitgenormaliseerd door alles in categorie te stoppen. Is merk (ford, opel) ook een categorie en zonee waarom niet? Ongetwijfeld heb je zeer valide redenen voor dit vreemde datamodel, ik ben benieuwd...
 
Dan Me

Dan Me

26/01/2011 10:48:39
Quote Anchor link
Het gaat hier niet om het datamodel. Deze is goed en kan volgens mij niet veel mis aan zijn.

item
category (id, parent_id)
item_category

Daarnaast is bovenstaande data fictie. Ik heb gewoon een situatie waarin ik veel categorieën heb op verschillende niveaus waaraan items gekoppeld kunnen worden. Niet meer en niet minder.

Het probleem waar jullie mij kunnen helpen is:

Waarom zou deze query zo langzaam zijn bij een tabel met 60.000 items.
Ik ben vast niet de eerste met een tabel welke dit aantal records bevat.

Alvast bedankt.
 
John D

John D

26/01/2011 11:08:08
Quote Anchor link
Een tabel met 60.000 records is datatechnisch gezien geen grote tabel en zal op zich geen performance problemen opleveren. Het ligt altijd aan de manier waarop je de tabel uitvraagt. Worden de indexen goed gebruikt of heb je (herhalende) full-table scans? Je moet full-table scans vermijden en wegwerken. Hoe is je query plan?
 
Dan Me

Dan Me

26/01/2011 11:27:37
Quote Anchor link
Dat dacht ik dus ook.

Het antwoord ligt dus ergens inderdaad bij de queries.

Misschien dat jij me dan kan helpen.
Hierbij wat meer info van wat ik gebruik:

item
-id (PK)
-type (offroad,rally,straat,race)

category
-id (PK)
-parent_id
-name (rood)

item_in_category
-id (PK)
-item_id (FK)
-category_id (FK)

Nogmaals bovenstaande data is fictie.

Nu heb ik bijv. 3000 type rally auto's en 60.000 type straat auto's.
De query waar het om gaat, heeft altijd betrekking op 1 type auto.

Echter als ik dus de SELECT beperk met het volgende, gaat de snelheid nog steeds niet omhoog.

SELECT car.id
FROM car_in_category cc
JOIN car c ON car.id = cc.car_id
WHERE cc.category_id IN (119456,119458,119460,119462,119464,119738)
AND car.type = "straat"
GROUP BY car.id
HAVING COUNT(*) = 6;
Gewijzigd op 26/01/2011 11:28:57 door Dan Me
 
John D

John D

26/01/2011 12:06:53
Quote Anchor link
maak eens een explain om te kijken wat er gebeurt met je query.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
EXPLAIN
SELECT car.id
FROM car_in_category cc
JOIN car c ON car.id = cc.car_id
WHERE cc.category_id IN (119456,119458,119460,119462,119464,119738)
AND car.type = "straat"
GROUP BY car.id
HAVING COUNT(*) = 6;

en beoordeel het resultaat.
 
Dan Me

Dan Me

26/01/2011 12:38:04
Quote Anchor link
Bij deze:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
id     select_type     table         type     possible_keys         key         key_len     ref             rows     Extra
1     SIMPLE             c             index     PRIMARY             PRIMARY     3             NULL             77751     Using index
1     SIMPLE             cc             ref     car_id,category_id     car_id         3             db.car.id         2         Using where


Hoop dat je hier een beetje uit komt, krijg het niet echt recht..
Gewijzigd op 26/01/2011 12:41:09 door Dan Me
 
John D

John D

26/01/2011 12:55:54
Quote Anchor link
Ziet er normaal uit, er worden 77751 rows opgehaald uit table c
Hoe snel kan je systeem i/o dat verwerken en wat doet de having count(*) in de query?
Op welk platform (server) doe je deze bewerking?
 
Dan Me

Dan Me

26/01/2011 13:10:47
Quote Anchor link
HAVING COUNT(*) heeft te maken dat ik alleen de items wil hebben die aan ALLE categorieën zijn gekoppeld. Dus geen OR situatie.

Ik doe deze bewerking op een Linux CentOS systeem.
Intel(R) Xeon CPU @ 2.53 GHz

Zou toch goed moeten zijn?

Hoe zou jij die 77751 rows verminderen? Ik hoef in principe niet te weten hoeveel items ik heb. Als ik maar weet dat het in ieder geval meer dan 0 zijn?
 
John D

John D

26/01/2011 13:23:28
Quote Anchor link
Wat is je uiteindelijke output? Wat verwacht je daadwerkelijk als output?
Je krijgt nu namelijk minimaal 77751 records in beeld en dat kost even tijd.
 
Dan Me

Dan Me

26/01/2011 13:27:04
Quote Anchor link
Nee de output is gegroupeerd (GROUP BY product.pid) dus krijg wel minder resultaten. Maar ik ben het ermee eens dat dit te veel is. Helemaal als je vervolgens hier niet veel mee doet. Ik controleer hiermee alleen of ik een resultaat heb,

Ik heb in ieder geval deze query nodig om te controleren of ik een resultaat heb middels de beschikbare waardes (119456,119458,119460,119462,119464,119738). Dat mag dus ook korter zijn. Een simpele limit toepassen werkt niet..
 
John D

John D

26/01/2011 13:42:58
Quote Anchor link
Zodra je kan beperken op de grote tabel krijg je minder output en dus minder i/o waardoor de query sneller resultaat geeft. Moet je dit steeds processen neem dan Oracle ipv MySQL en run je query op 8 cpu cores tegelijk. Succes verzekerd.
 
Dan Me

Dan Me

26/01/2011 13:49:32
Quote Anchor link
Ok, heb je ook een suggestie om de query zo te wijzigen dat ik minder rows tegen kom?
 
John D

John D

26/01/2011 14:27:02
Quote Anchor link
Bijvoorbeeld WHERE merk=BMW and bouwjaar=2010 and model=320
Ik neem aan dar je merk, bouwjaar en model niet in categorie stopt omdat dat dan juist te maken heeft met te ver uitnormaliseren en je performance niet te goede komt. In de 3e normaalvorm horen merk, bouwjaar en model tot de entiteit CAR omdat ze maar 1x voor kunnen komen bij CAR.
 
Dan Me

Dan Me

26/01/2011 14:45:22
Quote Anchor link
Er zijn zoveel verschillende mogelijkheden. Zie de category meer als specificatie. Dan is dit niet te doen om apart op te slaan en jouw situatie na te bootsen. De specs/categorieen zijn in mijn systeem van te voren niet bekend en zijn er meer dan 400...
 
John D

John D

26/01/2011 14:48:11
Quote Anchor link
neem dan Oracle ipv MySQL en run je query op 8 cpu cores tegelijk. Succes verzekerd.
 
Dan Me

Dan Me

26/01/2011 15:08:18
Quote Anchor link
Ja.. dat is natuurlijk niet zo simpel he..
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.