Ich würde den Ausschluss-Join ohne Unterabfragen schreiben:
SELECT p.productid
FROM products p
INNER JOIN producttags AS t ON p.productid = t.productid
LEFT OUTER JOIN producttags AS x ON p.productid = x.productid
AND x.tag IN ('Motorcycle', 'Green')
WHERE p.active = 1
AND t.tag IN ( 'Ford', 'Black', 'Skateboard' )
AND x.productid IS NULL;
Stellen Sie sicher, dass Sie einen Index für Produkte über die beiden Spalten (aktiv, Produkt-ID) in dieser Reihenfolge haben.
Sie sollten auch einen Index für Produkttags über den beiden Spalten (productid, tag) in dieser Reihenfolge haben.
Eine weitere Abfrage, die ich ausführen muss, ist so etwas wie alle (Auto) oder (Skateboard) oder (Grün UND Motorrad) oder (Rot UND Motorrad).
Manchmal sind diese komplexen Bedingungen hart für den MySQL-Optimierer. Eine gängige Problemumgehung besteht darin, UNION zu verwenden, um einfachere Abfragen zu kombinieren:
SELECT p.productid
FROM products p
INNER JOIN producttags AS t1 ON p.productid = t1.productid
WHERE p.active = 1
AND t1.tag IN ('Car', 'Skateboard')
UNION ALL
SELECT p.productid
FROM products p
INNER JOIN producttags AS t1 ON p.productid = t1.productid
INNER JOIN producttags AS t2 ON p.productid = t2.productid
WHERE p.active = 1
AND t1.tag IN ('Motorcycle')
AND t2.tag IN ('Green', 'Red');
PS:Ihre Tagging-Tabelle ist keine Entity-Attribute-Value-Tabelle.