langsamer Shop bei vielen Kategorien (24253)

Hallo zusammen, da ich immer die Meldung erhalte „Ihr Beitrag sieht nach Spam aus.“, teile ich mal mein Anliegen auf.

Hintergrundinfos: Wir möchten bei uns einen Online-Shop mit gebrauchten Artikeln (jeder Artikel nur einmal vorhanden, ständiger Zu- und Abfluss) eröffnen. Um Shopware mal zu testen habe ich mir in einer virtuellen Maschine (VirtualBox) eine Test-System mit einem 64bit Debian installiert. Die Hardware in der virtuellen Maschine ist mit 4x Intel Core i3-2120 @3,3GHz und 1,8GiB Arbeitsspeicher ziemlich großzügig ausgelegt. Shopware ist in der aktuellen Version 4.0.7, PHP in 5.3.3 und mysql 5.1.66 installiert. Mit der REST-API habe ich angefangen aus unserer eigenen Software heraus Artikel hochzuladen, was auch sehr einfach funktioiniert.

Problem: Aktuell bin ich gerade bei 41668 Artikeln in 24253 Kategorien und habe das Problem das der Shop gar nicht mehr reagiert weil der mysql-query zu lange läuft. Indem ich im Backend-Plugin “Advanced Menu” die Anzahl der Ebenen auf 2 gesetzt habe ist die Reaktionszeit auf 60-200 Sekunden gesunken, so das der Shop nach einer bestimmten Zeit doch noch angezeigt wird. Als Ursache für diese miserable Performance habe ich folgende mysql-Abfrage in der mysql-slow.log ausgemacht: # Time: 130403 16:43:29 # User@Host: root[root] @ localhost [] # Query\_time: 159.112047 Lock\_time: 0.000246 Rows\_sent: 1 Rows\_examined: 35128459 SET timestamp=1365000209; SELECT SQL\_CALC\_FOUND\_ROWS ( s0\_.`right` - s0\_.`left` -1 ) /2 AS sclr0, ( SELECT COUNT( s1\_.id ) AS dctrn\_\_1 FROM s\_categories s2\_ INNER JOIN s\_articles\_categories s3\_ ON s2\_.id = s3\_.categoryID INNER JOIN s\_articles s1\_ ON s1\_.id = s3\_.articleID AND ( s1\_.active =1 ) WHERE s2\_.active =1 AND ( s2\_.`right` \<= s0\_.`right` AND s2\_.`left` \>= s0\_.`left` ) ) AS sclr1, ( SELECT count( s4\_.id ) AS dctrn\_\_2 FROM s\_categories s4\_ WHERE s4\_.`left` \< s0\_.`left` AND s4\_.`right` \> s0\_.`right` AND s4\_.level \< s0\_.level AND s4\_.active \<\>1 ) AS sclr2, s0\_.id AS id3, s0\_.parent AS parent4, s0\_.description AS description5, s0\_.position AS position6, s0\_.`left` AS left7, s0\_.level AS level8, s0\_.`right` AS right9, s0\_.metakeywords AS metakeywords10, s0\_.metadescription AS metadescription11, s0\_.cmsheadline AS cmsheadline12, s0\_.cmstext AS cmstext13, s0\_.active AS active14, s0\_.template AS template15, s0\_.blog AS blog16, s0\_.showfiltergroups AS showfiltergroups17, s0\_.external AS external18, s0\_.hidefilter AS hidefilter19, s0\_.hidetop AS hidetop20, s0\_.noviewselect AS noviewselect21, s0\_.changed AS changed22, s0\_.added AS added23, s5\_.id AS id24, s5\_.albumID AS albumID25, s5\_.name AS name26, s5\_.description AS description27, s5\_.path AS path28, s5\_.type AS type29, s5\_.extension AS extension30, s5\_.userID AS userID31, s5\_.created AS created32, s5\_.file\_size AS file\_size33, s6\_.id AS id34, s6\_.categoryID AS categoryID35, s6\_.attribute1 AS attribute136, s6\_.attribute2 AS attribute237, s6\_.attribute3 AS attribute338, s6\_.attribute4 AS attribute439, s6\_.attribute5 AS attribute540, s6\_.attribute6 AS attribute641 FROM s\_categories s0\_ LEFT JOIN s\_media s5\_ ON s0\_.mediaID = s5\_.id LEFT JOIN s\_categories\_attributes s6\_ ON s0\_.id = s6\_.categoryID LEFT JOIN s\_categories\_avoid\_customergroups s8\_ ON s0\_.id = s8\_.categoryID LEFT JOIN s\_core\_customergroups s7\_ ON s7\_.id = s8\_.customergroupID AND ( s7\_.id =1 ) WHERE s0\_.active =1 AND s0\_.`left` \>2 AND s0\_.`right` \<48503 AND s0\_.level \<=2 GROUP BY s0\_.id HAVING ( sclr1 \>0 OR s0\_.external IS NOT NULL OR s0\_.blog =1 ) AND COUNT( s7\_.id ) =0 AND sclr2 =0 ORDER BY s0\_.`left` ASC LIMIT 1; Wie man sieht sind von dieser Abfrage gute 35 Millionen Zeilen betroffen. Beim hochladen der Artikel hat der Server 44 Top-Level-Kategorien angelegt was unserer internen Struktur entspricht. Das dies das Template zerschießt ist erstmal unwichtig.

Meine Lösungsansätze: 1. die Kategoriestruktur vereinfachen, das Minimum das möglich wäre sind 2 Ebenen Kategorien. - Pro: am einfachsten umzusetzen, wahrscheinlich am effektivsten - Kontra: teilweise zu viele Artikel in den Kategorien deshalb unübersichtlich 2. ein Modul schreiben das die Kategorien sortiert, so das nur die Kategorien mit den meisten Artikeln in der Menuleiste angezeigt werden. - Pro: Das Template wird automatisch bereinigt, Kategorien können automatisch deaktiviert werden wenn sie nur noch wenige Artikel enthalten - Kontra: bringt das wirklich einen Geschwindigkeitsvorteil wenn nur einige Top-Kategorien im Menü oben und in der linken spalte wieder alle angezeigt werden Ich frage mich jetzt welche (Misch-)Lösung wird am meisten bringen? Hat sonst noch jemand Erfahrungen mit so vielen Kategorien? Oder muss ich mich komplett nach einer anderen Software umschauen, anstatt noch mehr Zeit hier zu investieren?

Hallo, hängt das denn unmittelbar mit dem Advanced-Menü zusammen? Also verändert sich die Performance gravierend, wenn du das Plugin z.B. testweise deaktivierst?

Vielen Dank für die schnelle Antwort. Habs mal deaktiviert, Cache geleert. Hat seit ca. einer Stunde geladen. Seit dem ist die CPU-Auslastung dauerhaft bei allen CPU’s ca. 80%. Plugin wieder aktiviert, Cache geleert. Jetzt zeigt er den Shop nach mehreren Minuten wieder an. Hab wieder mehrere Einträge in der mysql-slow.log. Die CPU-Last bleibt so hoch. Erst wenn ich den mysql-Server im Terminal von Hand neustarte pendelt die sich wieder bei 7-8% ein.

Magst du mal bitte ein EXPLAIN der Abfrage posten?

 id select\_type table type possible\_keys key key\_len ref rows Extra 1 PRIMARY s0\_ const PRIMARY PRIMARY 4 const 1 1 PRIMARY s4\_ const PRIMARY NULL NULL NULL 1 1 PRIMARY s5\_ const categoryID categoryID 5 const 0 unique row not found 1 PRIMARY s7\_ ref articleID articleID 4 const 1 Using index 1 PRIMARY s6\_ const PRIMARY PRIMARY 4 const 1 Using index 2 DEPENDENT SUBQUERY s2\_ ALL PRIMARY,left NULL NULL NULL 22033 Using where 2 DEPENDENT SUBQUERY s3\_ ref articleID,categoryID,articleID\_2 categoryID 4 sw4\_0\_7-test.s2\_.id 3 2 DEPENDENT SUBQUERY s1\_ eq\_ref PRIMARY PRIMARY 4 sw4\_0\_7-test.s3\_.articleID 1 Using where 

Das Problem liegt offenbar in dem Subselect mit der Count() Funktion (sclr1), bei dem MySQL keinen Index verwenden kann. Dieses Subselect wird für jedes äußere Result (d.h. sinngemäß für jede Kategorie) ausgeführt, was die extrem langsame Ausführungsgeschwindigkeit erklärt. Ich versuche am Montag mal ein wenig Zeit freizuschaufeln um zu schauen, ob man das durch einen Index allein lösen kann…

Versuch’s mal bitte damit und schau, ob es etwas ändert (gerne wieder mit nem EXPLAIN). Ich habe leider gerade keine ausreichend große Datenmenge zur Hand, daher habe ich es jetzt doch freihändig gemacht. ALTER TABLE `s_categories` ADD INDEX `menu_active` (`active` ASC, `left` ASC, `right` ASC, `level` ASC) ;

Vielen Dank für den Tip. Ich habe jetzt die Kategorie-Struktur angepasst, so das ich jetzt nur noch knapp 11500 Kategorien habe. Die Ladezeit ist damit schon etwas besser. Habe deine Abfrage ausgeführt. Cache geleert und den Server vorschichtshalber komplett neugestartet. Habe jetzt 1.400.580 betroffene Zeilen in durchschnittlich 3,3 Sekunden im Gegensatz zu den vorherigen 21.289.296 in ca. 45 Sekunden. Das ist zwar noch nicht optimal, aber damit kann ich erstmal arbeiten. Ich werde jetzt ein Modul schreiben was die Top-Kategorien schön durch sortiert, damit diese nicht mehr das Template zerstören. Sollte auch noch etwas an Geschwindigkeit bringen wenn ich das richtig verstanden habe. Kann etwas dauern, muss mich erstmal einlesen.

Wie bereits erwähnt fehlt mir leider eine entsprechend große Testdatenbank (wir sind selbst nicht mal auf der 4er Version) und die nötige Zeit. Ich kenne ebenso keine Details wie und wo diese Abfrage zum Einsatz kommt, aber ich bin mir sicher, dass man das auch noch ganz anders lösen könnte…auf der anderen Seite bin ich immer wieder erstaunt darüber, dass man im Verhältnis offenbar kaum Zeit und Energie in die Datenbank, und alles was damit zu tun hat, gesteckt hat. Sein übriges tut vermutlich Doctrine dazu (die Abfrage sieht autogeneriert aus). Schade. Wenigstens hat der Index schon mal eine signifikante Verbesserung gebracht, immerhin…

Mit dieser Abfrage werden anscheinend die Kategorien abgefragt. Warum die so komplex sein muss weiss ich auch nicht. Allerdings überlege ich gerade erst ob ich weiter in Shopware einsteigen soll, hab daher kein Hintergrundwissen. P.S.: Ich glaube der beste Weg ist die Kategoriestruktur weiter zu vereinfachen. Habe jetzt einfach einen Teil der Kategorien in den Eigenschaften abgebildet. Zum Glück kann ich auf unserer Seite das flexibel anpassen.

Hi, in der Version 4.1 von Shopware werden wir gerade die Performance bei vielen Kategorien noch einmal erheblich verbessern. Wir hoffen, dass Sie spätestens dann keine Probleme mehr mit der Menge an Kategorien haben werden. Viele Grüße, Marcel

Vielen Dank für die Info Marcel, wisst ihr schon wann ungefähr das Release rauskommt? Ich habe eine Zeitlimit um meinem Vorgesetzten ein Konzept inkl. Zeitplan vorzulegen. nochmals Danke Vito

Ich möchte jetzt keine Anti-Werbung betreiben. Wir nutzen selbst Shopware und man muss ganz klar sagen, dass das System sehr viel bietet, ausgesprochen hübsch ist und dazu in der Grundversion Opensource zur Verfügung steht! Auch sind (ursprünglich) 20.000 Tausend Kategorien sicher nicht wenig und wahrscheinlich eher nicht der Regelfall. Aber: wir haben uns selbst für Shopware entschieden, weil uns klar war, dass wir voraussichtlich nie mehr als ein paar Tausend Artikel in 1-2 Dutzend Kategorien haben werden. Ich habe bereits viel zu viel Negatives über SW4 zusammen mit vielen Kategorien / Artikeln oder Varianten gelesen. Auch würde ich mich persönlich nicht an den Strohhalm SW4.1 klammern. Wenn du es auf der jetzigen Basis akzeptabel hinbekommst (zumal Caching, etc ja noch hinzukäme), dann kann man es sicher versuchen. Wenn SW4.1 dann die erhofften Zuwächse bringt, umso besser. Das Problem ist einfach, dass SW4 seit einem Jahr in der Beta ist und seit einem halben Jahr final. Und trotzdem gibt es an verschiedenen Stellen deutliche Performanceprobleme (siehe Backend). Dass neue Software Probleme hat, ist klar, aber was halt Kopfzerbrechen bereitet, ist wie ovi angedeutet hat, dass man das Gefühl hat, bestimmte Bereiche seien einfach nicht wirklich fertig gedacht. Und dann stellt sich auch die Frage, ob der Shop rein konzeptionell je wirklich schnell werden wird - siehe Doctrine. Solche Dinge könnte man dann auch nicht einfach von heute auf morgen ändern. Schöne Grüße Ade