Eigene Twig-Funktion wird scheinbar nicht richtig gecached - Performance-Problem

Hallo,

ich habe eine eigene Twig-Funktion gebaut, die Unterkategorien aus der Datenbank ausliest. Wir haben über 100.000 Kategorien auf bis zu 5 Hierarchie-Ebenen.

Die Funktion sieht so aus:

public function getSubCategories(SalesChannelContext $salesChannelContext, string $parentId)
    {

        $criteria = new Criteria();

        $criteria->addFilter(new EqualsFilter('parentId', $parentId));
        $criteria->addSorting(new FieldSorting('name', FieldSorting::ASCENDING));

        $criteria->addState(Criteria::STATE_ELASTICSEARCH_AWARE);

        $context = $salesChannelContext->getContext();
        
        $subCategoryRepository =  $this->categoryRepository->search($criteria, $context)->getEntities();

        return $subCategoryRepository;
}

Die Twig-Funktion wird je nach Hierarchie-Ebene bis zu 20.000 mal aufgerufen. Ich weiß, das ist extrem, aber in SW5 hat das super geklappt, sobald die Seite einmal in den Cache geladen war. Da war die Ladezeit dann ca. 4 Sekunden (Für uns absolut akzeptabel für die Datenmenge).

In SW6 performt die Seite trotz aktiviertem Cache übel: 19 Sekunden.
Ich habe elasticsearch aktiviert und auch redis als cache. APP_ENV=prod
SW-Version: 6.5.8.7

Ich hab schon mit redis und redis_tag_aware getestet. Macht auch keinen Unterschied:

framework:
    cache:
        #app: cache.adapter.redis_tag_aware
        app: cache.adapter.redis
        default_redis_provider: 'redis://redis:6379'

Ich hab auch versucht, die Daten direkt aus der DB zu ziehen:

        $connection = \Shopware\Core\Kernel::getConnection();

        $languageId = $salesChannelContext->getContext()->getLanguageId();

        $sql = 'SELECT hex(c.ID) as id, t.name
	            FROM
                    category c
                    inner join category_translation t on t.category_id = c.id
                where hex(c.parent_id) = "'.$parentId.'"
	                AND hex(t.language_id)="'.$languageId.'"
	            ORDER BY t.name';

        $A_categories = $connection->executeQuery($sql)->fetchAll();

        return $A_categories;

Aber auch das bringt keinen Performance-Gewinn.

Und ich hab probiert, alle notwendigen Daten aus der DB in einem einzigen SQL zu holen, so dass ich die Twig-Funktion nur einmal aufrufen müsste, aber da die Abfrage in der mySQL Workbench schon 41 Sekunden braucht, habe ich den Ansatz auch wieder verworfen.

Mir fällt langsam nix mehr ein :frowning:
Kann ich irgendwo am Cache noch was einstellen oder optimieren?
In SW5 hatte ich das Gefühl, dass die Seite an sich in den Cache geladen wurde. In SW6 erscheint mir das alles sehr granular mit den verschiedenen Caches und funktioniert scheinbar - zumindest in meinem Fall - nur suboptimal.
Bin für jeden Tipp dankbar.

Du kannst noch so viele caches gegen das Problem werfen - du solltest dich um die Ursache kümmern. 20.000 rekursive Aufrufe ist schlichtweg falsch.

Viele Grüße

Das war mir klar, dass diese Antwort kommt. Hilft mir aber bei meinem Problem nicht weiter.

Ich bin mir dessen bewusst, dass das suboptimal ist. Aber dennoch gibt es Gründe dafür bei einer Datenbank mit ca. 400.000 Artikeln.

Und wie gesagt, hat es bei SW5 ja auch funktioniert mit dem Cache. Also nützt es wohl doch was „viele caches gegen das Problem zu werfen“.

Hast Du noch einen hilfreichen Vorschlag?

Das ist der einzig wirklich sinnvolle und definitiv hilfreichste Vorschlag den man dir geben kann. Ich glaube nicht dass du hier einen Entwickler findest der ernsthaft anderer Meinung ist.

Viele Grüße

Zum fachlichen Ansinnen kann ich nichts beitragen.
Dein SQL läuft schneller, wenn du keine Funktion (hex) auf den Inhalt der Tabelle c.parent_id und t.language_id machst. Stattdessen solltest du entweder die Parameter $parentId und $languageId als „unhex“ oder die where Bedingung auf andere Felder anwenden, wo der hex(…) bereits in der Datenbank steht und das Feld dann auch indexiert ist.
Kurz gesagt: Berechnen und dann vergleichen ist schlecht, direkt vergleichen in der Datenbank auf einem indizierten Feld wirkt Wunder.

Oh, super Tipp. :+1: Vielen Dank! :grinning:

where c1.parent_id = unhex('4e611ad5e7a0d8955134b40e7fe9d34b')
	AND t1.language_id= unhex('2fbb5fe2e29a4d70aa5854ce7ce3e20b')

0.016 sec in der Workbench.

Da hätte ich eigentlich auch selber drauf kommen können, aber manchmal sieht man den Wald vor lauter Bäumen nicht.

Vielen Dank für den hilfreichen Tipp. Werde jetzt den direkten SQL-Ansatz nochmal in Angriff nehmen und alles über eine einzige Query abfackeln.

Alternativ ginge auch

WHERE c1.parent_id = 0x4e611ad5e7a0d8955134b40e7fe9d34b
	AND t1.language_id= 0x2fbb5fe2e29a4d70aa5854ce7ce3e20b

OK. Vielen Dank für den Tipp. Werde ich auch ausprobieren und schauen, ob es von der Performance her einen Unterschied macht. :+1:

Wahrscheinlich nicht viel, das andere war viel wichtiger.

Dieses Thema wurde automatisch 30 Tage nach der letzten Antwort geschlossen. Es sind keine neuen Antworten mehr erlaubt.