Vinzenz Mai: Kann ich diese MySQL-Anfrage optimieren?

Beitrag lesen

Hallo Eddie,

folgende MySQL-Anfrage scheint zu kompliziert zu sein, die Datenbank braucht ewig dafür:

=====================================
SELECT DISTINCT c.*
FROM contentTable c, rel_content_category1 rel1, rel_content_category2 rel2
WHERE
(
c.id = rel1.contentID
AND
(rel1.catID = 'ki' OR
  rel1.catID = 'fm' OR
  rel1.catID = 'nr')
)

OR
(
c.id = rel2.contentID
AND
rel2.catID = '6'
)

Dabei ist das ja eigentlich garnich so kompliziert!

Es ist nicht kompliziert, es ist umfangreich. Du betrachtest hier das kartesische Produkt von drei Tabellen.

außerdem sind die Tabellen garnicht so riesig:
  contentTable c: 500 Einträge
  rel_content_category1 rel1: 7000 Einträge
  rel_content_category1 rel2: 500 Einträge

Ich versteh das nicht? Wo liegt der Haken?

Somit muss das DBMS ca. 500 x 7000 x 500 Kombinationen, also ungefähr 1.750.000.000 durcharbeiten. Du wunderst Dich, dass das lange dauert?

Teile ich die Anfrage in zwei Anfragen, geht es ruckzuck:

=====================================
SELECT DISTINCT c.*
FROM contentTable c, rel_content_category1 rel1, rel_content_category2 rel2
WHERE
c.id = rel1.contentID
AND
(rel1.catID = 'ki' OR
  rel1.catID = 'fm' OR
  rel1.catID = 'nr')

Ja, hier hast Du einen (impliziten) Join. Viel schöner formulierst Du dies mit

  
SELECT DISTINCT c.*  
FROM contentTable c,  
INNER JOIN rel_content_category1 rel1  
ON c.id = rel1.contentID  
WHERE rel1.catID IN ('ki', 'fm', nr')

für die folgende gilt das Gleiche, es ist ein Join vorhanden:

=====================================
SELECT DISTINCT c.*
FROM contentTable c, rel_content_category1 rel1, rel_content_category2 rel2
WHERE
c.id = rel2.contentID
AND
rel2.catID = '6'

  
SELECT DISTINCT c.*  
FROM contentTable c,  
INNER JOIN rel_content_category1 rel2  
ON c.id = rel2.contentID  
WHERE rel1.catID = 6

Ich versteh das nicht? Wo liegt der Haken?

Bei der von Dir verwendeten MySQL-Version, die Du hättest angeben sollen. UNION bietet sich hier an:

  
SELECT DISTINCT c.*  
FROM contentTable c,  
INNER JOIN rel_content_category1 rel1  
ON c.id = rel1.contentID  
WHERE rel1.catID IN ('ki', 'fm', nr')  
UNION  
SELECT DISTINCT c.*  
FROM contentTable c,  
INNER JOIN rel_content_category1 rel2  
ON c.id = rel2.contentID  
WHERE rel1.catID = 6

UNION gibt es in MySQL ab Version 4.0.0, die Wahrscheinlichkeit, dass Dir UNION zur Verfügung steht ist somit recht hoch.

Weiterhin lege ich Dir die Lektüre der Beta-Versionen der Feature-Artikel von Rouven und mir ans Herz.

Freundliche Grüße

Vinzenz