Hallo beisammen,
wir entwickeln eine Sportseite auf Basis von Typo3 4.5 mit einer Extension auf Extbase/Fluid. Allerdings sind wir jetzt an ein Performance-Problem gestossen, dass sich wie folgt auswirkt (als Beispiel nehme ich unsere Ergebnistabelle, da es dort besonders schwer wiegt):
Bild: images.trackmyrace.com/…/tmr_screenshot.png
Die Tabelle baut sich dynamisch aus bis zu 32 Objekten eines Repositories pro Pagination-Seite zusammen, welche über Eingabefelder über den Spalten gefiltert und sortiert werden können und per Ajax aktualisiert wird. Durch diese Dynamik fällt klassisches Caching als Totschlaglösung schonmal flach, d.h. die Seite muss an sich schon eine vernünftige Performanz zeigen, damit man sich beim Durchforsten der Tabelle nicht zu Tode warten muss.
Aktuell braucht die Ajax-Seite (ohne die letzte Spalte, die etwas zu viele if/thens noch hat) ~2.15s Serverseitig, was eindeutig zuviel ist. Davon werden ~99% in der Extension verbraten laut Typo3 Profiler und nach ein bisschen weiterem Timing sind davon nur ~300ms der reine Code in der Action (was auch noch Optimierungsbedarf hat, aber erstmal nicht der Bottleneck ist), also ca. 1,7s gehen für Extbase Initialisierung und das Fluid rendering drauf. Liegt das jetzt an an Fluid/Extbase generell, sprich ist es einfach nicht für die Generierung einer so dynamischen Tabelle geeignet, oder ist es einfach nur eine ungeschickt gewählte Kombination aus viewhelpern?
Hier das View-Template:
{namespace tmr=Tx_TmrCore_ViewHelpers}
<f:for each="{results}" as="result">
<f:cycle values="{0: 'odd', 1: 'even'}" as="zebraClass">
<tr class="content_row result {f:if(condition:'{result.name} == {starter}',then:'highlight')}" rel="{f:uri.action(action:'individual', addQueryString:'true', additionalParams:'{tx_tmrcore_event: { controller: \'Event\', event: event, course: result.course, single_result: result } }')}">
<tmr:tableBody each="{columns}" as="column" key="val" iteration="it" result="{result}">
<td valign="middle" class="{zebraClass}{f:if(condition:'{it.isFirst} == 1',then:' first')}">
{val}
</td>
</tmr:tableBody>
</tr>
</f:cycle>
</f:for>
<f:render partial="Results/Download" arguments="{event: event, course: course, list: list, results: results, count: count}" />
<f:render partial="Results/Pagination" arguments="{action: 'resultstable', lastpage: lastpage, page: page}"/>
Zur Erklärung: Die beiden Partials unten geben den Tabellenfooter mit einem Link zum dynamischen PDF-Download der Tabelle und der Pagination aus. Beide Zusammen nehmen etwa 100ms und sollte daher auch erstmal nur 2.-rangig für Optimierung sein.
Der tmr:tableBody Viewhelper ist eine Kombination aus for- und render-Viewhelper und iteriert über die Spaltenkonfiguration in {columns} (welche im Prinzip nur die Feldnamen enthält, die aktuell angezeigt werden sollen), liest den entsprechenden Wert aus {result} aus und rendert, falls vorhanden, ein eigenes Partial für diese Spalte, ansonsten den eigenen Content. Solch ein eigenes Partial wird für 4 Spalten genommen, welche den Textinhalt über einen weiteren Viewhelper nach einer festen Anzahl Zeichen abschneiden und den vollen Inhalt über das title-Attribut als Tooltip ausgeben.
Abgesehen davon, dass es sich hier um ein O(m*n) Problem handelt - gibt es noch Möglichkeiten die Performance zu optimieren? Ich habe auch bereits versucht, die {results} nicht als QueryResult, sondern als Raw Array zu holen. Das hilft aber nur relativ wenig und ich verliere die Flexibilität eines echten Model Objects mit echten Gettern. Wenn es aber nicht anders geht, verzichte ich gerne auch auf etwas Flexibilität.
Wir werden auch mal XDebug auf dem Server installieren um noch genauer zu profilen, ich wäre aber dennoch über sämtliche Hinweise dankbar.