T-Rex: Kostet Rendern wirklich soooo viel Zeit

Moin,

heute habe ich eine eher philosophische Frage und eher weniger ein Problem.

Ich hab da eine Datenbank-Tabelle mit ca. 10.000 Zeilen. Dazu habe ich ein cms System, wo ich unter anderem alle Zeilen auf einmal ausgeben lassen kann. Pro Zeile habe ich 15 Spalten. Ergo müssen mindestens 10.000 * 15 = 150.000 HTML Elemente gerendert werden (+ Menü und Suchformular etc.) .

Wenn ich mir wirklich alle Zeilen ausgeben lasse, dauert das Rendern einige Minuten. Lasse ich mir hingegen nur eine Zusammenfassung ausgeben, dauert es ein paar wenige Sekunden. Rein von der Logik ändert sich nichts. Es werden immer noch alle Datensätze gelesen, bearbeitet etc... nur das Render wird gespart bzw. am Ende kommt ein "Summe".

Das ohne Rendern die ganze Geschichte schneller läuft ist mir schon klar. Mir waren die Dimensionen aber nicht bewusst. Ich meine das Rendern läuft min. 100 mal langsamer. Das erstaunt mich dann schon sehr.

Gruß erstaunT-Rex

  1. Hallo T-Rex,

    hast du geprüft, ob das Rendern oder die Datenübertragung die Zeit verschlingen?

    Gruß
    Jürgen

    1. Da es lokal ist, entfällt diese Frage für mich.

      1. Haben die Spalten feste breiten?

        1. nein haben sie nicht

          1. Dann probiers mal damit. s.a. Dedlfix

      2. Moin,

        wie kommen denn die Daten aus der Datenbank in den Browser?

        Viele Grüße
        Robert

        1. Ich lade sie per php aus der Datenbank verarbeite sie weiter und übergebe sie an eine eigene programmierte Viewschnittstelle. In meinem Beispiel wird nur das letzte echo unterdrückt. Ansonsten wird die gleiche Logik durchlaufen.

          Das heißt, wäre mein aktueller Fall ein normaler Anwenderfall und würde ich ihn noch optimieren wollen, würde ich die Weitergabe an die Viewschicht noch unterdrücken. Aber darum geht es ja nicht. Wenn ich etwas optimieren wollen würde, dann würde ich ja das Ausgeben an den Browser optimieren wollen - also quasi genau die andere Seite der Medaille.

          Gruß (1) xeR-T-Rex (100)

          1. Moin,

            Ich lade sie per php aus der Datenbank verarbeite sie weiter und übergebe sie an eine eigene programmierte Viewschnittstelle. In meinem Beispiel wird nur das letzte echo unterdrückt. Ansonsten wird die gleiche Logik durchlaufen.

            obwohl das – soweit ich das richtig verstanden habe – nur über das Loopback Device läuft, werden trotzdem einiges an Daten zwischen den Prozessen transportiert. Das macht auch etwas aus – auch wenn das Rendern wohl der teuerste Teil ist.

            Viele Grüße
            Robert

  2. Tach!

    Ergo müssen mindestens 10.000 * 15 = 150.000 HTML Elemente gerendert werden (+ Menü und Suchformular etc.) .

    Wenn ich mir wirklich alle Zeilen ausgeben lasse, dauert das Rendern einige Minuten.

    Es kommt darauf an, was der Browser konkret zu tun bekommt. Soll alles nur einfach untereinander in separaten Elementen hingeschrieben werden, geht es vermutlich schneller, als wenn der Browser eine Tabelle zu erstellen hat, wo die Breite der Spalten erst nach dem letzten gelesenen Inhalt berechnet werden kann. Die Developertools im Browser geben auch bei Performance-Problemen Auskunft, was wieviel Zeit verbraucht.

    dedlfix.

  3. Hallo T-Rex,

    Kostet Rendern wirklich soooo viel Zeit

    Ja. Das tut es.

    Ich habe mir eine lokale Bastelseite geschrieben, die in einer PHP Loop 10000 Zeilen raushaut. Das Ergebnis sieht so aus:

    <script>
    let t0 = Date.now();
    </script>
    <table>...</table>
    <script>
    let t1 = Date.now();
    window.addEventListener("load", function() {
       let t2 = Date.now();
       console.log(`DOM: ${t1-t0}, 1st event: ${t2-t1}, total: ${t2-t0}`);
    });
    </script>
    

    Das Eventhandling beginnt erst, wenn die erste Layoutphase vollständig gelaufen ist, d.h. das load Event wartet, bis die Tabelle auf dem Bildschirm ist. Damit kann ich die Zeit für das Rendering nach Aufbau des DOM messen.

    Wenn die Tabelle stumpf rausgehauen wird, mit table-layout:auto und ohne feste Spaltenbreiten, habe ich bei mir eine DOM-Zeit von ca 10s. Die Zeit bis zum ersten Event beträgt dann noch 200ms.

    Wenn ich über CSS für feste Spaltenbreiten sorge und table-layout:fixed setze, sinkt die Zeit für den DOM-Aufbau auf 6,5s.

    Geht das besser? Klar doch:

    Wenn ich die Tabelle initial auf display:none setze und das nach Aufbau der Table entferne - etwa so:

    <table id="foo" style="display:none">
    ...
    </table>
    <script>
      document.getElementById("foo").style.removeProperty("display");
    </script>
    

    ändert sich das Timing dramatisch. Das DOM ist dann nach 165ms fertig. Dafür kommt das load-Event erst 3,3s später. In Summe bedeutet das: Es ist nur 1/3 der Zeit vom Anfang. Ich sehe zwar nichts von der Tabelle, bis sie fertig aufgebaut ist, aber genau dieses "nichts sehen = nichts rendern" bringt auch das Tempo.

    So richtig fix wird es aber nur, wenn Du auf die Darstellung von 10000 Zeilen komplett verzichtest. Das letzte Beispiel zeigt: Der reine DOM Aufbau ist blitzschnell. Was Zeit kostet, ist die Darstellung auf dem Bildschirm.

    Mach also eine CSS-Regel

    tr:not(.match) { display:none; }
    

    und programmiere am Client etwas, das dem Anwender nur die benötigten Zeilen zeigt. Zeige nicht mehr als 300 Zeilen an, oder so. Zwinge die Anwender dazu, sich das, was sie brauchen, mit deiner Suchfunktion herauszusuchen.

    Du kannst auch einen CSS Paginierer bauen (der von JS angesteuert wird, logischerweise). Dazu musst Du das CSSOM (CSS Objektmodell) verwenden.

    Mach Dir diesen style-Abschnitt:

    <style id="paginator"> tr { display: none; } tr:nth-child(n+1):nth-child(-n+100) { display: table-row; } </style>

    Damit würdest Du die ersten 100 Rows zu sehen bekommen. Wenn Du nun bspw. nicht die Zeilen 1-100, sondern 301-400 anzeigen willst, änderst Du per Javascript den Selektor der zweiten Regel in diesem Abschnitt:

    function paginateTo(from, to) {
       let paginationRule = document.getElementById("paginator").style.rules[1];
       paginationRule.selectorText = "tr:nth-child(n+"+from+"):nth-child(-n+"+to+")";
    }
    

    Ein Aufruf paginateTo(301,400) würde den Selektor dann passend ändern, auf tr:nth-child(n+301):nth-child(-n+400)`. Das ist jetzt nicht universell, sondern speziell auf's Beispiel zugeschnitten. Eine generische Lösung wäre sicherlich etwas komplizierter.

    Eine Mischung von Matching und diesem Paginator funktioniert heute noch nicht, dazu fehlt die of-Option von nth-child (CSS Selectors Level 4). Die ist noch nirgends implementiert. Aber im Zweifelsfall kann man auch von Hand paginieren und sich die passenden Indexe heraussuchen.

    Das sind so die Möglichkeiten, wie man die Sache beschleunigen kann. Jedes Rendering, das man weglassen kann, ist ein gutes Rendering.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Das Eventhandling beginnt erst, wenn die erste Layoutphase vollständig gelaufen ist, d.h. das load Event wartet, bis die Tabelle auf dem Bildschirm ist. Damit kann ich die Zeit für das Rendering nach Aufbau des DOM messen.

      Du erhälst auf jeden Fall einen groben Richtwert, mit dem sich sicher auch schon gut arbeiten lässt. Für eine exakte Messung eignen sich die in Browsern eingebauten Performance-Profiler aber noch besser. Der Browser durchläuft verschiedene Phasen, bis er etwas auf dem Bildschirm anzeigt, ganz grob: Download, Parsing, Rendering, Painting. Diese Phasen laufen aber nur konzeptionell streng nacheinander ab. In der Praxis geschieht das nebenläufig. Mit den DevTools lässt sich feinmaschig feststellen wie viel Zeit der Browser in welcher Phase verbringt.

      Und nebenbei: Aufgezeichnete Performance-Profile lassen sich auch wunderbar teilen 😉

    2. Also wow ... ich bin immer noch Sprachlos. Eigentlich wollte ich mich nur ein wenig Auskotzen. Aber dann bekommt man hier so tolle Tipps - Danke!

      Also einen Pager habe ich bereits via PHP implementiert. Normalerweise sollen auch nur 100-1000 Zeilen pro Seite erscheinen. Die 10.000 (mittlerweile 15.000) sind nur für mich bei einem speziellen Fall wo ich wirklich alle Datensätze sehen und nacheinander durchscrollen wollte.

      Wie auch immer, ich konnte das Rendern mit deinem simplen Trick 1-2 Minuten auf wenige Sekunden verkürzen. Noch sauberer wäre es bestimmt via Ajax die Resultate zu laden. Dann könnte man auch 100er Häppchen weise die Zeilen laden und hätte gleich deine Idee implementiert, dass man dem User schonmal ein paar Zeilen zum bewundern gibt. Aber ehrlich gesagt ... das braucht mein cms aktuell nicht. Mit der aktuellen Lösung bin ich sehr zufrieden und habe wieder etwas gelernt.

      Gruß T-RolFan

      1. Hallo T-Rex,

        nacheinander durchscrollen

        15000 Sätze? Welcher merkwürdige Anwendungsfall ist das???

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Ich hab einen Backtest für den Dax programmiert und schaue mir meine Tradingstrategie an, die auf die letzten 50 Jahre (bis 1971) getestet wird. Dabei habe ich Flags gesetzt wann etwas gekauft und verkauft wird, damit ich die Zeilen schneller finde wo dies passiert.

          Das ist aber nur die Detail Ansicht, die ich brauche um generell eine Veränderung auch vor den Trade-Tagen zu sehen. Ich hab dann noch eine schnellere Ansicht, wo ich nur die getätigten Trades sehe. Wenn ein Backtest in der schnellen Ansicht gut aussieht, schaue ich ihn mir in der Detailansicht an.

          Gruß T-Dax

  4. Hello,

    hast Du in der Tabelle eventuell auch Sekundär-Requests drin? Bilder, Ajax, trallala...

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.
    1. Hallo Tom,

      hast Du in der Tabelle eventuell auch Sekundär-Requests drin? Bilder, Ajax, trallala...

      guter Hinweis. 😀

      Übrigens dachte ich heute mittag im ALDI bei mir um die Ecke schon, ich hätte dich gesehen! Die Ähnlichkeit war verblüffend. Erst aus der Nähe und bei genauem Hinsehen war dann klar, dass es doch jemand anders war. Ein Doppelgänger.
      Wäre ja auch praktisch ausgeschlossen. Hier in BaWü??

      May the Schwartz be with you
       Martin

      --
      Theorie ist, wenn eigentlich jeder weiß, wie's gehen müsste, und es geht doch nicht.
      Praxis ist, wenn's geht, obwohl es keiner so richtig versteht.
      Bei uns sind Theorie und Praxis vereint: Nichts geht, und keiner weiß, warum.
      1. Übrigens dachte ich heute mittag im ALDI bei mir um die Ecke schon, ich hätte dich gesehen! Die Ähnlichkeit war verblüffend. Erst aus der Nähe und bei genauem Hinsehen war dann klar, dass es doch jemand anders war. Ein Doppelgänger.
        Wäre ja auch praktisch ausgeschlossen. Hier in BaWü??

        Hat der sich auch neue Leihschuhe besorgt?