29. April 2020 – Development

Performante Such- und Filterabfragen in VueJS-Webapplikationen mit vielen Daten

 

Werden auf einer Webapplikation strukturierte Daten in tabellarischer Form ausgegeben, müssen diese oft durchsucht und/oder gefiltert werden können. Anhand eines praktischen Beispiels aus einem unserer letzten grossen Projekte zeige ich auf, welche technischen Fragen man sich in Bezug auf die Geschwindigkeit von Suchabfragen und das Laden und Anzeigen vieler Datensätze stellen sollte.

 

 

Plattform für Verwaltung strukturierter Daten

Wir haben in den letzten Monaten an einer mandantenfähigen und flexibel konfigurierbaren Webplattform namens «Flexiplan» gearbeitet. Das Frontend (Browseransicht) wurde komplett mit VueJS (Javascript) umgesetzt. Im Backend nutzen wir Pimcore als CMS (PHP/MySQL).

Kernaufgabe des Tools ist es, unseren Kunden die einfache Erfassung und Verwaltung von strukturierten Daten zu ermöglichen – webbasiert. Die verwalteten Daten können später auf unterschiedlichste Weise ausgegeben (Reports, PDF) oder z.B. auf anderen Websites integriert werden (API-Schnittstelle). 

Zentrales Element auf der grafischen Benutzeroberfläche von Flexiplan ist die Listenansicht mit Such- und Filtermöglichkeiten.

 

Ausgangslage

Wir mussten uns für unsere Listenanzeige und für Suche, Filter und Sortierung folgende Fragen stellen:

  • Mit wie vielen Datensätzen rechnen wir ungefähr resp. wie skalierbar soll das Ganze sein?
  • Soll die Suche/Filterung im Frontend oder Backend passieren?
  • Wie laden wir Daten nach?

 

Möglichkeiten für die Implementation

Um eine  Suche, Filterung und Sortierung umsetzen zu können, kommen ganz grundsätzlich zwei Implementationsmöglichkeiten in Frage:

  • Frontend (Client)
  • Backend (Server)

 

Clientseitige Suche/Filterung (mit VueJS)

Die Daten werden direkt in der Browseransicht durchsucht, gefiltert und sortiert. Keine Datenbankabfrage.

Vorteile:
  • Einfache und schnelle Umsetzung von Suche, Filtern und Sortierung.
  • Serverseitig kein zusätzlicher Programmieraufwand nötig (Einsatz von SQL-Abfragen).
  • Daten werden nicht immer wieder neu vom Server geladen.
  • Anpassen von Resultatlisten bei Tastendruck/Eingabe (Live-Search) ist durch den Einsatz von VueJS bereits gewährleistet.
Nachteile: 
  • Sämtliche Daten müssen im Browser geladen sein.
  • Kann bei vielen Datensätzen schnell langsam werden (500’000+), daher wenig skalierbar in Bezug auf Performance.

 

Serverseitige Suche/Filterung

Im Browser wird eine Anfrage an den Server gestellt. Mittels SQL wird die Suche direkt auf der Datenbank durchgeführt und das Resultat an den Browser zurückgeliefert.

Vorteile:
  • SQL ist sehr schnell zum Abfragen von grossen Datenmengen.
  • Für eine Suche müssen nicht bereits alle Daten im Frontend geladen sein.
Nachteile: 
  • Höherer Programmieraufwand.
  • Eine Live-Search im Frontend wird nur durch den zusätzlichen Einsatz von AJAX (asynchrones Javascript) möglich.
  • Daten werden immer wieder neu vom Server an den Client geschickt.

 

Daten nachladen durch Blättern und Infinite Scrolling

Eine gängige Methode, um Ladezeiten im Browser zu verzögern, ist der Einsatz von Paging (Blätterfunktion) oder Infinite Scrolling. Datensätze werden erst dann geladen, wenn sie angezeigt werden müssen. Ein gutes Beispiel hierfür ist Youtube. Beim Scrollen nach unten werden nach und nach immer mehr Videos angezeigt und geladen.

 

Unsere Lösung

Da es sich bei unserer Anwendung um eine mandantenfähige Plattform handelt, kam für uns nur die serverseitige Variante in Frage, damit die Performance im Fall von sehr grossen Datenmengen nicht unter einer Suche/Filterung leidet und die Skalierbarkeit gewährleistet ist.

Wir haben unsere API so erweitert, dass in einer ersten Abfrage nur eine simple ID-Liste der Datensätze vom Server an den Client geschickt wird, was mehrere Vorteile zur Folge hat:

  • Von Anfang an ist klar, wie viele Datensätze vorhanden sind.
  • Nutzdaten können in einer zweiten Anfrage dann nachgeladen werden, wenn sie gebraucht werden. Daraus resultiert ein deutlicher Geschwindigkeitsgewinn.

Die effektiven Nutzdaten werden dann nachgeladen und angezeigt, wenn der Benutzer am Scrollen ist und die entsprechenden IDs aus der Liste sich im Sichtbereich des Browserfensters befinden.

Die Nutzdaten werden clientseitig im VueJS-Store gespeichert, damit einmal geladene Nutzdaten selbst bei einer erneuten Suche/Filterung nicht nochmals geladen werden müssen, denn es ändert sich lediglich die Anzahl bzw. Sortierreihenfolge der ID-Liste.

Wenn Datensätze beim Scrollen nachgeladen und immer weiter unten angefügt werden, wächst der HTML-Baum im Browser entsprechend mit. Ab einer gewissen Länge kann dies zu Darstellungsproblemen bis hin zum Browserabsturz führen. Um dies zu verhindern, haben wir die Virtual-Scrolling-Technik eingesetzt.

Virtual Scrolling bedeutet, dass nur die aktuell im Viewport angezeigten Daten sich im HTML-Baum befinden. Beim Scrollen verändert sich das HTML aber ständig. Der Unterschied zum einfachen unteren Anfügen ist, dass vorherige Elemente aus dem Baum wieder entfernt werden und anstehende vorgeladen. Dadurch wird die Anzahl der DOM-Elemente konstant gehalten, wodurch die Leistung der Anwendung gesteigert wird.

Für den Besucher sieht es aus, als würde endlos nachgeladen. Tatsächlich wird aber nur der jeweilige Ausschnitt ersetzt.

Demo: https://akryum.github.io/vue-virtual-scroller/#/recycle

Den Scrollbalken auf der rechten Seite müssen wir «fälschen», denn tatsächlich gibt es gar keinen so langen HTML-Inhalt, der einen Scrollbalken erzeugen würde. 

Was uns nun aber zugutekommt, ist, dass wir zu jedem Zeitpunkt unsere gesamte ID-Liste und somit die Anzahl der Listeneinträge kennen. Damit können wir berechnen, wie gross der Scrollbalken sein müsste und wo sich die jeweilige Scrollposition befindet.

Fazit

Die Art der Umsetzung von performanten Such- und Filterabfragen in einer Webapplikation geht immer mit der Frage der Skalierbarkeit und der zu erwartenden Datenmengen einher. Eine Implementation kann daher von sehr schnell und einfach bis hin zu hochgradig komplex variieren. Eine einzige Lösung gibt es selten, kommte es doch sehr auf verschiedene technische Parameter an.

Bei kleinen, geschlossenen Anwendungen mit wenig Daten kann man die Funktionalität von Suchen und Filter durchaus vollständig im Frontend ansiedeln, was gerade mit VueJS sehr einfach umzusetzen ist. Bei skalierbaren Applikationen, wo die Datenmengen schnell wachsen können, empfiehlt es sich, von Anfang an einen Ansatz zu wählen, der unabhängig von clientseitigen Limitierungen funktioniert. Zusammengefasst:

  • Komplexe Suchabfragen mit grossen Datenmengen sind mit SQL direkt auf der Datenbank immer am schnellsten.
  • Serveranfragen/-antworten wann immer möglich zusammenfassen und zwischenspeichern, viele einzelne «Subrequests» vermeiden.
  • Nutzdaten nicht unnötig bei jeder Anfrage neu laden, sondern zwischenspeichern (Thema: ID-Liste).
  • In der Anzeige beim Nachladen darauf achten, dass der Browser nicht bis ans Limit mit Datensätzen aufgefüllt wird (Thema: Infinite Scrolling, Virtual Scrolling).

#theCodingLove

 

Blog-Artikel teilen:

 

Möchten Sie regelmässig über neue Blog-Beiträge informiert werden?

 

 

0 Kommentare

Teilen Sie uns Ihre Meinung mit