MySQL Gruppierte Ausgabe - Optimierung

justme69

Im RL-Dauerstress
ID: 99452
L
25 April 2006
676
13
Hallo zusammen,

ein kleines SQL-Problem verursacht mir Kopfzerbrechen.

Mal vereinfachen:
ich habe 4 Tabellen.
Artikel (art),
keys: article_id​
Produktgruppe (pg),
keys: product_group_id​
Produktgruppe_Artikel (pga) und
keys: article_id, product_group_id​
Gruppen_Pgs (g_pg)
keys: source_pg_id, target_pg_id​
Ich habe nun Einträge in g_pg die mir sagen, das Produktgruppe 33 verweist auf 123 und 234 (2 rows in der Tabelle)

Ich möchte nun jeweils 5 Artikel in den Produktgruppen angezeigt bekommen, die aufgrund der Einträge in g_pg definiert sind
Alle anzeigen zu lassen ist kein Thema - oder für jede Produktgruppe jeweils einen - auch kein Problem.

Alle anzeigen:
PHP:
select * 
from article art,
( 	select pga.article_id, pga.product_group_id
	from product_group_article pga
	where pga.product_group_id IN ( select target_pg_id  from the_look where cat_id = 1 and source_pg_id = 1653 )
	order by RAND()
) as t 
where art.article_id = t.article_id
ein zusätzliches 'group by t.product_group_id' liefert einen Artikel pro Produktgruppe

Ich hab mysql-Server 5.0.77 installiert.

Any ideas? :mrgreen:

--- Optimierungsfragen --- s.u.

PS: ja ich weiss - select * ist scheisse - wird auch in der endgültigen Fassung geändert ;) :ugly: :evil:
 
Zuletzt bearbeitet:
Mit dieser Query müsstest Du pro Produktgruppe bis zu fünf Artikel_IDs zurückbekommen. Schau mal, ob das so funktioniert:

PHP:
SELECT A.artikel_id, a.product_group_id
FROM 
   Produktgruppe_Artikel a 
INNER JOIN 
   Produktgruppe_Artikel b
ON a.artikel_id <= b.artikel_id
AND a.product_group_id = b.product_group_id
WHERE a.product_group_id IN
(
   SELECT target_pg_id  
   FROM
      Gruppen_Pgs
   WHERE
      source_pg_id = 33
)
GROUP BY A.artikel_id, a.product_group_id
HAVING COUNT(*) < 6
 
Hab doch noch Fragen...

Da das kartesische Produkt von
PHP:
product_group_article a INNER JOIN product_group_article b ON a.product_group_id = b.product_group_id and a.article_id <= b.article_id
ca 1,4 Mio Einträge liefert, ist die Abfrage recht teuer, dh nicht tauglich, wenn diese etliche Male pro Sekunde ausgeführt werden soll....
(Viele User online)

Bei anderen DBs ist die Anzahl der DS des Joins noch größer - über 3 Mio.

Welche Optimierungsmöglichkeiten/Varianten gibts?
 
Es ist ein INNER JOIN.
Wenn mySql schlau ist, wird zuerst die WHERE-Bedingung abgearbeitet und dann nur die betroffenen Produktgruppen geJOINed. Wenn die einzelnen Produktgruppen nicht allzugross sind, dann sollte es auch kein Performanceproblem geben.

Alternativ kannst Du auch das probieren:

PHP:
SELECT A.artikel_id, a.product_group_id 
FROM  
   Gruppen_Pgs gps
INNER JOIN
   Produktgruppe_Artikel a  
ON gps.target_pg_id  = a.product_group_id  
AND gps.source_pg_id = 33 
INNER JOIN  
   Produktgruppe_Artikel b 
ON a.artikel_id <= b.artikel_id 
AND a.product_group_id = b.product_group_id 

GROUP BY A.artikel_id, a.product_group_id 
HAVING COUNT(*) < 6
 
Das produkt wäre dann 'nur' noch ca. 600.000 DS, läuft aber an sich recht schnell. Das hatte ich währenddessen auch (ähnlich) eingebaut...

Ich brauche zu diesen beiden Feldern noch die Daten aus der Artikel Tabelle...
Wenn ich diese mit hineinbringe wird's teuer....
aus 0,2 sec werden ca 6 sec....

Die article_id ist jeweils key, bzw primary key.

PHP:
SELECT A.artikel_id, a.product_group_id , art.*
FROM   
   Gruppen_Pgs gps 
INNER JOIN 
   Produktgruppe_Artikel a   
ON gps.target_pg_id  = a.product_group_id   
AND gps.source_pg_id = 33  
INNER JOIN   
   Produktgruppe_Artikel b  
ON a.artikel_id <= b.artikel_id  
AND a.product_group_id = b.product_group_id ,
article art

where art.article_id = b.article_id

GROUP BY A.artikel_id, a.product_group_id  
HAVING COUNT(*) < 6

Ich könnte das jetzt zwar auf 2 SQLs auftrennen doch ist der Verbindungsaufbau bzw der prepare/execute Aufwand auch aufwendig...
wenns also noch Optimierungen gibt ;)
 
Wieviele Artikeldatensätze werden denn durchschnittlich gelesen.
5 Artikel pro Gruppe, aber wievele target_pg_id - Gruppen gibts denn ca. pro source_pg_id ?
Wenn es nicht allzuviele sind, würde ich es so machen:


PHP:
SELECT art.*
FROM artikel art
WHERE art.artikel_id IN 
(
SELECT A.artikel_id
FROM   
   Gruppen_Pgs gps 
INNER JOIN 
   Produktgruppe_Artikel a   
ON gps.target_pg_id  = a.product_group_id   
AND gps.source_pg_id = 33  
INNER JOIN   
   Produktgruppe_Artikel b  
ON a.artikel_id <= b.artikel_id  
AND a.product_group_id = b.product_group_id  

GROUP BY A.artikel_id, a.product_group_id  
HAVING COUNT(*) < 6
)
 
Zuletzt bearbeitet:
neee, so kommt er gar nicht zum Ende....

Artikel ca 20.000,
produktgruppen ca 50
artikel sind oft in 2 produktgruppen
target_pg_id zur zeit max. 3

Gelesen werden sollen (an der Stelle) max 15 Artikel, egal wieviele targets es gibt...

Werde es wohl doch auf 2 selects aufteilen müssen - hab auch keine zeit noch lange zu probieren ;)

Vielen Dank, hast mich weitergebracht ;)