DB-Abfrage schlecht?

Hallo zusammen, wir haben in unserem SW 4.0.4 mit langen Ladezeiten bei der Artikelabfrage zu kämpfen. Das öffnen einer Kategorie dauern nicht selten über 5 Sekunden und das Filtern einer Artikeleigenschaft mindestens genau so lange. Vor diesem Vorwand habe ich die Abfrage mal von einem Profi überfliegen lassen, welcher mit folgendes Feedback gegeben hat: [quote]CROSS SELF JOIN! Sehr übel! Wie viele Datensätze sind in s_categories und s_articles_categories? Nehmen wir einfach mal an, dass 20 in der einen und 200 in der anderen sind, dann entstehen durch den Cross über diese Tabellen schon 80.000 Results… wenn es 40 und 400 sind, dann wären es schon 640.000. Jedes dieser Results wird dann mit den „normalen“ Joins in Verbindung gesetzt…da kann es schon mal etwas länger dauern :slight_smile: Keine FULL_GROUP-Option gesetzt! Evtl. fehlerhaftes Ergebnis![/quote] Der Shop wird 30.000 Artikel und 15.000 Kategorien haben. Wobei es wegen der 5 Subshops also insgesamt knapp 90.000 Kategorien geben wird. Ist es richtig, dass die Abfrage “so übel” ist? Hat jemand einen Ansatz, wie hier optimiert werden kann? Danke + Grüße

Hallo Phil, kannst du uns bitte noch mitteilen um welches Query es sich genau handelt? Dann können wir dies ggf. optimieren und alternativen zum Cross Join suchen :slight_smile: Danke und viele Grüße, Benjamin Cremer :shopware:

Aus reinem Interesse… 15.000 Kategorien? Ich nehme an das sind als Workaround so viele geworden? Oder sind das tatsächlich 15.000 Kategorien in einer klassischen Menüstruktur?

Nabend, folgend die Abfrage, auf welche sich dieser Thread bezieht: SELECT a.id as articleID, aDetails.id AS articleDetailsID, a.notification as notification, weight, aDetails.ordernumber, a.datum, aDetails.releasedate, additionaltext, aDetails.shippingfree, aDetails.shippingtime,instock, a.description AS description, description\_long, aSupplier.name AS supplierName, aSupplier.img AS supplierImg, a.name AS articleName, topseller as highlight, IFNULL(p.price, p2.price) as price, laststock, sales, IF(p.pseudoprice,p. pseudoprice,p2.pseudoprice) as pseudoprice, aTax.tax, taxID, aDetails.minpurchase, aDetails.purchasesteps, aDetails.maxpurchase, aDetails.purchaseunit, aDetails.referenceunit, aDetails.unitID, pricegroupID, pricegroupActive, IFNULL(p.pricegroup,IFNULL(p2. pricegroup,'EK')) as pricegroup, attr1,attr2,attr3,attr4,attr5, attr6,attr7,attr8,attr9,attr10, attr11,attr12,attr13,attr14, attr15,attr16,attr17,attr18,attr19,attr20, --cd.discount, IFNULL((SELECT 1 FROM s\_articles\_details WHERE articleID=a.id AND kind=2 LIMIT 1), 0) as variants, (a.configurator\_set\_id IS NOT NULL) as sConfigurator, IFNULL((SELECT 1 FROM s\_articles\_esd WHERE articleID=a.id LIMIT 1), 0) as esd, IFNULL(( SELECT CONCAT(AVG(points),'|',COUNT(\*)) as votes FROM s\_articles\_vote WHERE active=1 AND articleID=a.id), '0.00|00') as sVoteAverange, IF(DATEDIFF(NOW(), a.datum)\<=30,1,0) as newArticle, IF(aDetails.sales\>=0,1,0) as topseller, IF(aDetails.releasedate\>CURDATE(),1,0) as sUpcoming, IF(aDetails.releasedate\> CURDATE(), aDetails.releasedate, '') as sReleasedate FROM s\_categories c, s\_categories c2, s\_articles\_categories ac JOIN s\_articles AS a ON a.id=ac.articleID AND a.mode = 0 AND a.active=1 JOIN s\_articles\_details AS aDetails ON aDetails.id=a.main\_detail\_id JOIN s\_articles\_attributes AS aAttributes ON aAttributes.articledetailsID=aDetails.id JOIN s\_core\_tax AS aTax ON aTax.id=a.taxID LEFT JOIN s\_articles\_avoid\_customergroups ag ON ag.articleID=a.id AND ag.customergroupID=1 LEFT JOIN s\_articles\_supplier AS aSupplier ON aSupplier.id=a.supplierID LEFT JOIN s\_articles\_prices p ON p.articleDetailsID=aDetails.id AND p.pricegroup='EK' AND p.to='beliebig' LEFT JOIN s\_articles\_prices p2 ON p2.articledetailsID=aDetails.id AND p2.pricegroup='EK' AND p2.to='beliebig' WHERE c.id=5 AND c2.active=1 AND c2.left \>= c.left AND c2.right \<= c.right AND ac.articleID=a.id AND ac.categoryID=c2.id AND ag.articleID IS NULL GROUP BY a.id ORDER BY aDetails.sales DESC, aDetails.impressions DESC, a.id, a.id LIMIT 0, 12 SELECT COUNT(DISTINCT a.id) count FROM s\_categories c, s\_categories c2, s\_articles\_categories ac JOIN s\_articles AS a ON a.id=ac.articleID AND a.mode = 0 AND a.active=1 JOIN s\_articles\_details AS aDetails ON aDetails.id=a.main\_detail\_id LEFT JOIN s\_articles\_avoid\_ customergroups ag ON ag.articleID=a.id AND ag.customergroupID=1 WHERE c.id=5 AND c2.active=1 AND c2.left \>= c.left AND c2.right \<= c.right AND ac.articleID=a.id AND ac.categoryID=c2.id AND ag.articleID IS NULL SELECT fv.optionID AS id, COUNT(DISTINCT a.id) AS count, fo.id AS optionID, fo.name AS optionName, f.id AS groupID, f.name AS groupName, fv.value AS optionValue, fv.id AS valueID, st.objectdata AS optionNameTranslation, st2.objectdata AS groupNameTranslation, st3.objectdata AS valueTranslation FROM s\_categories c, s\_categories c2, s\_articles\_categories ac JOIN s\_filter\_articles fa ON fa.articleID=ac.articleID JOIN s\_filter\_values fv ON fv.id=fa.valueID JOIN s\_filter\_options fo ON fo.id=fv.optionID AND fo.filterable = 1 JOIN s\_articles a ON a.id=ac.articleID AND a.active =1 AND a.changetime \<= NOW() JOIN s\_filter f ON f.id=a.filtergroupID LEFT JOIN s\_filter\_relations fr ON f.id = fr.groupId AND fo.id = fr.optionId LEFT JOIN s\_articles\_avoid\_customergroups ag ON ag.articleID=fa.articleID AND ag.customergroupID=1 LEFT JOIN s\_core\_translations AS st ON st.objecttype='propertyoption' AND st.objectkey=fv.optionID AND st.objectlanguage='' LEFT JOIN s\_core\_translations AS st2 ON st2.objecttype='propertygroup' AND st2.objectkey=f.id AND st2.objectlanguage='' LEFT JOIN s\_core\_translations AS st3 ON st3.objecttype='propertyvalue' AND st3.objectkey=fv.id AND st3.objectlanguage='' WHERE c.id=5 AND c2.active=1 AND c2.left \>= c.left AND c2.right \<= c.right AND ac.articleID=a.id AND ac.categoryID=c2.id AND ag.articleID IS NULL GROUP BY fv.id ORDER BY fr.position, fo.name ASC, IF(f.sortmode=1, TRIM(REPLACE(fv.value,',','.'))+0, 0), IF(f.sortmode=2, COUNT(\*) , 0) DESC, IF(f.sortmode=3, fv.position, 0), fv.value @loesungsmittel: Es sind zirka 15.000 klassiche Kategorien. Wir vertreiben technische Produkte und müssen die Kategorien ziemlich detailiert herunterbrechen. Gruß

Das sind ja im Schnitt nur 2 Produkte pro Kategorie? Hab ich noch nie gesehen. Darf man fragen, um welche techischen Produkte es sich dabei handelt? Grüße Erik

Hallo, die Menge Kategorien (mit Subshops 90.000) wird mit Sicherheit schwierig bzw. müsste man das wirklich einmal in einem Probelauf genau prüfen. Bisher kenne ich auch kein System, welches annähernd an diese Menge kommt. Ich empfehle auf jeden Fall nicht mit Kategorien in diese Tiefe zu gehen, sondern damit wirklich nur die generelle Struktur abzubilden und ansonsten mit Eigenschaften/Filtern zu arbeiten. Das bietet zudem viel mehr Möglichkeiten als Kategorien. Gerade wirklich auf das Filtern, Suche oder zukünftige Plugins bezogen. Kategorien sind in Shopware gedacht um grobe Einteilungen vorzunehmen bzw. die Struktur vorzugeben und Erlebniswelten zu gestalten, um den Kunden anzusprechen und den perfekten Einstieg in die Bereiche zu gewährleisten. Um bis ins letzte Detail Artikel zuzuweisen, also im Prinizp zu filtern, ist da nicht vorgesehen. Das nur unabhängig von der genannten Query :wink:

Guten Morgen, bei dem Produkt handelt es sich um Reifen. Um den Kategorieaufbau kommen wir nicht herum, da die Kunden über AdWords direkt in die richtige Kategorie geleitet werden. Der Kunde kann theoretisch auch in der Kategorie erster Ebene (z.B. /Sommerreifen) bleiben und dann in >10.000 Artikeln anfangen zu filtern. Doch kann er auch direkt über Google in die richtige Kategorie gebracht werden (z.B. /Sommereifen/PKW/195-65R15) und erhält direkt nur passende Produkte. Ähnliche Artikel die dem Kunden vorgeschlagen werden, haben daduch die gleiche Reifendimension. Alles andere sehe ich hier nicht zielführend. Bin jedoch natürlich für Vorschläge aufgeschlossen. Jeder Artikel ist in mindestens 6 Kategorien eingeteilt. Dadurch sind es unterm Strich mehr als 2 Produkte pro Kategorie. Aber zurück zur eigentlichen Frage: Hat jemand einen Ansatz, wie diese sehr langsame Abfrage optimiert werden kann? Grüße

Also, anstelle alle möglichen Kombinationen in den Kategorien abzubilden, würd ich lieber mal heraus finden, wie man den Filter über die URL vorbelegen kann. Dann wird auf Dauer nicht nur AdWords gefüttert, sondern der Kunde hat auch das Interesse, sich im Shop umzusehen. Ich meine, versetz Dich mal in die Sichtweise des Kunden: Ich als Kunde bin jetzt über AdWords in Deinen Shop gekommen. Somit hast Du an Google schon mal Geld bezahlt; auch wenn ich am Ende nix kaufe. Ich bin jetzt z.B. in der Kategorie für 195/50R15T von Pirelli, möchte aber lieber noch mit Michelin, Goodyear, Hankook und Barum (damit’s auch mal billig gibt :wink: ) vergleichen. Als Kunde will ich aber nicht zig mal durch diverse Kategorien zurück und wieder vorwärts klicken. Was mache ich also irgendwann? Genervt den Shop verlassen. Das gleiche gilt, wenn ich über AdWords auf dem o.g. Reifen lande, aber eigentlich nicht Gescheindigkeitsindex T, sondern V brauche. Oder z.B. einen anderen Tragfähigkeitsindex. Auch dann muss ich erst wieder eine oder mehrere Kategorien nach oben und dann wieder tiefer eintauchen. Und die Anzahl der Kategorien, die ich nach oben muss, bestimmst Du im Voraus, auch wenn die Hierarchie für meine Situation vielleicht sehr unpassend ist, also zu einer langwierigen Klickerei wird. Und die Wahrscheinlichkeit, dass ich über AdWords zu einer Artikel-Auswahl komme, die nicht 100%-ig zu meinem Wunsch passt, dürfte sehr hoch sein. Wenn ich aber in den Shop einsteige und z.B. einfach in der Kategorie Sommerreifen/PKW lande und als Filter bereits Breite:195, Querschnitt:50, Felgendurchmesser:15, Geschwindigkeitsindex:T (mit Angabe der Geschwindigkeit in km/h) und Hersteller:Pirelli eingestellt ist, dann könnte ich den Filter auf den Hersteller löschen und schon hätte ich alle Hersteller. Oder ich lasse den Hersteller stehen, lösche den Tragfähigkeitsindex und setze ihn dann auf V. Wenn man das ganze noch mit einem Filter für bestimmte Preis-Bereiche ergänzt, dürfte jeder Kunde schnell glücklich werden. Zumal ja die Anzahl der Artikel neben dem Filter-Attribut steht und das Attribut gleich ausgeblendet wird, wenn es keine passenden Artikel gibt. Du siehst, wenn man die Fülle an Ausgangssituationen betrachtet, dann hilft ein Filter dem Kunden viel weiter als eine Flut von Kategorien. Bedenke auch den Aufwand beim Anlegen neuer Kategorien, wenn mal neue Artikel hinzu kommen sollten. Und aus Erfahrung kann ich sagen: Wenn die Filter-Eigenschaften erstmal stehen, dann ist es auch kein Problem, diese mit dem ab Werk enthaltenen Import-Plugin den Artikeln zu zu ordnen (zumindest per XML). Gruß, Nico.

[quote=“Nico Minuth”]Also, anstelle alle möglichen Kombinationen in den Kategorien abzubilden, würd ich lieber mal heraus finden, wie man den Filter über die URL vorbelegen kann. Dann wird auf Dauer nicht nur AdWords gefüttert, sondern der Kunde hat auch das Interesse, sich im Shop umzusehen. Ich meine, versetz Dich mal in die Sichtweise des Kunden: Ich als Kunde bin jetzt über AdWords in Deinen Shop gekommen. Somit hast Du an Google schon mal Geld bezahlt; auch wenn ich am Ende nix kaufe. Ich bin jetzt z.B. in der Kategorie für 195/50R15T von Pirelli, möchte aber lieber noch mit Michelin, Goodyear, Hankook und Barum (damit’s auch mal billig gibt :wink: ) vergleichen. Als Kunde will ich aber nicht zig mal durch diverse Kategorien zurück und wieder vorwärts klicken. Was mache ich also irgendwann? Genervt den Shop verlassen. Das gleiche gilt, wenn ich über AdWords auf dem o.g. Reifen lande, aber eigentlich nicht Gescheindigkeitsindex T, sondern V brauche. Oder z.B. einen anderen Tragfähigkeitsindex. Auch dann muss ich erst wieder eine oder mehrere Kategorien nach oben und dann wieder tiefer eintauchen. Und die Anzahl der Kategorien, die ich nach oben muss, bestimmst Du im Voraus, auch wenn die Hierarchie für meine Situation vielleicht sehr unpassend ist, also zu einer langwierigen Klickerei wird. Und die Wahrscheinlichkeit, dass ich über AdWords zu einer Artikel-Auswahl komme, die nicht 100%-ig zu meinem Wunsch passt, dürfte sehr hoch sein. Wenn ich aber in den Shop einsteige und z.B. einfach in der Kategorie Sommerreifen/PKW lande und als Filter bereits Breite:195, Querschnitt:50, Felgendurchmesser:15, Geschwindigkeitsindex:T (mit Angabe der Geschwindigkeit in km/h) und Hersteller:Pirelli eingestellt ist, dann könnte ich den Filter auf den Hersteller löschen und schon hätte ich alle Hersteller. Oder ich lasse den Hersteller stehen, lösche den Tragfähigkeitsindex und setze ihn dann auf V. Wenn man das ganze noch mit einem Filter für bestimmte Preis-Bereiche ergänzt, dürfte jeder Kunde schnell glücklich werden. Zumal ja die Anzahl der Artikel neben dem Filter-Attribut steht und das Attribut gleich ausgeblendet wird, wenn es keine passenden Artikel gibt. Du siehst, wenn man die Fülle an Ausgangssituationen betrachtet, dann hilft ein Filter dem Kunden viel weiter als eine Flut von Kategorien. Bedenke auch den Aufwand beim Anlegen neuer Kategorien, wenn mal neue Artikel hinzu kommen sollten. Und aus Erfahrung kann ich sagen: Wenn die Filter-Eigenschaften erstmal stehen, dann ist es auch kein Problem, diese mit dem ab Werk enthaltenen Import-Plugin den Artikeln zu zu ordnen (zumindest per XML). Gruß, Nico.[/quote] Hey Nico, zunächst finde ich es super wie du das beschrieben hast. Danke! Mit dem was du sagst hast du auch vollkommen recht. Nur ist es so, dass die Kategorien beispielsweise nicht den Speed oder Loadindex enthalten. Sowohol diese beiden “Eigenschaften” als auch weitere, werden dann gefiltert. Also um die vielen Kategorien gibt es kein herumkommen. Das ist schon alles durchdacht. Das einzige Problem ist, dass die Abfragen so furchtbar lange dauern. Gibt es diesbezüglich schon was neues? Grüße

Hallo zusammen, wir hatten bei einem Kundenshop mal ein ähnliches Problem. Da gab es auch unzählige KFZ-Kategorien und Artikel, welche ein Benutzen des Shops quasi unmöglich gemacht haben. Wir haben das damals (war noch unter 3.5, aber vielleicht hilft der Ansatz weiter) so gelöst, dass wir die Artikel erst dann geladen haben, wenn eine bestimmte Unterkategorieebene erreicht wurde. Es macht ja wenig Sinn, alle Artikel im Hintergrund bereitzuhalten, wenn jemand auf “Sommerreifen” klickt. Im konkreten Fall war es dann so, dass wir den Besucher des Shops zuerst sein Fahrzeug haben auswählen lassen und dann wurden erst Artikel ausgegeben. Habe jetzt nicht auf dem Schirm, ob und was sich da mit Version 4 getan hat. Aber vielleicht ist es ja eine Überlegung wert, die DB-Abfragen ansich nicht zu verbessern sondern nur dann einzusetzen, wenn sie wirklich notwendig sind. Jan Philipp