Daily CheckIn
This commit is contained in:
parent
ebec44cdee
commit
1f34a0a382
13 changed files with 161 additions and 168 deletions
|
@ -14,7 +14,7 @@ Durch die nummerierten Präfixe können im Nachgang über die \textit{pgBadger}"
|
|||
werden. Wichtig hierbei ist noch, dass vor dem \textit{measrun}-Aufruf überprüft wird, ob die Docker-Container
|
||||
gestartet und initialisiert sind. Wenn dies nicht der Fall ist, laufen die Abfragen ins Leere. Am einfachsten ist das,
|
||||
wie dargestellt, über die Statistik von Docker zu ermitteln. Darüber wird überwacht, das die CPU-Auslastung auf ein
|
||||
niedriges Level fällt, danach kann das Skript für die Messungen gerufen werden.
|
||||
niedriges Level fällt, danach kann das Skript für die Messungen aufgerufen werden.
|
||||
|
||||
\includecode[bash]{chapters/thesis/appendix04_calling_script.sh}{lst:calling_script}{Calling Script}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
Für die Protokollierung der Abläufe im \ac{JSF} werden zwei Klassen benötigt. Über die Factory \ref{lst:logger_factory},
|
||||
wird die Wrapper"=Klasse in die Bearbeitungsschicht eingeschleust. Diese Wrapper"=Klasse \ref{lst:logger} beinhaltet
|
||||
dann die eigentliche Performance-Messung, inklusive der Ausgabe in die Log"=Datei des \textit{Glassfish}"=Servers.
|
||||
dann die eigentliche Performance"=Messung, inklusive der Ausgabe in die Log"=Datei des \textit{Glassfish}"=Servers.
|
||||
Zusätzlich muss in der Konfiguration \texttt{faces-config.xml} noch angepasst werden, wie in
|
||||
\ref{lst:logger_factory_activate}, um die Factory durch das System aufrufen zu lassen.
|
||||
|
||||
|
|
|
@ -3,12 +3,10 @@
|
|||
\chapter{Einleitung}
|
||||
\label{ch:intro}
|
||||
|
||||
\mytodos{Verena: Performance"=Verbesserung oder Perfromanceverbesserung?}
|
||||
|
||||
Die Akzeptanz und damit die Verwendung einer Software hängt von verschiedenen Kriterien
|
||||
ab. Hierbei ist neben der Stabilität und der Fehlerfreiheit die Performance beziehungsweise
|
||||
die Reaktionszeit der Software ein sehr wichtiges Kriterium. Hierfür muss sichergestellt
|
||||
werden, dass die Anwendung immer in kurzer Zeit reagiert oder entsprechende Anzeigen dargestellt werden
|
||||
werden, dass die Anwendung immer in kurzer Zeit reagiert oder entsprechende Anzeigen dargestellt werden,
|
||||
um eine längere Bearbeitung anzuzeigen.
|
||||
|
||||
%\section{Motivation}
|
||||
|
@ -53,48 +51,47 @@ eingesehen werden kann. Hierbei wurden sämtliche bislang bekannte Korrespondenz
|
|||
Briefe selbst werden im etablierten TEI"=Format gespeichert und über einen WYSIWYG"=Editor von den Editoren und
|
||||
Editorinnen eingegeben.
|
||||
|
||||
Das Projekt wurde anhand von bekannten und etablierten Entwurfsmustern umgesetzt um eine modulare und unabhängige
|
||||
Das Projekt wurde anhand von bekannten und etablierten Entwurfsmustern umgesetzt, um eine modulare und unabhängige
|
||||
Architektur zu gewährleisten, damit dies für weitere digitale Briefeditionen genutzt werden kann.
|
||||
|
||||
\section{Ziel der Arbeit}
|
||||
\label{sec:intro:goal}
|
||||
|
||||
Die aktuelle Umsetzung beinhaltet die bisher definierten Anforderungen vollständig, darunter fallen die
|
||||
Recherchemöglichkeiten, sowie auch die Eingabe und die Verarbeitung der Briefe. Ein größeres Problem hierbei ist die
|
||||
Recherchemöglichkeiten sowie auch die Eingabe und die Verarbeitung der Briefe. Ein größeres Problem hierbei ist die
|
||||
Performance der Oberfläche. Auf Grund der langen Abfragedauer des Datenbestandes leidet die Akzeptanz der Anwendung.
|
||||
|
||||
Das Ziel dieser Arbeit ist es, die Abfragedauer zu verringern, wodurch die Performance der Oberfläche signifikant
|
||||
verbessert wird. \mytodos{verena}
|
||||
verbessert wird.
|
||||
|
||||
\section{Gliederung}
|
||||
\label{sec:intro:structure}
|
||||
|
||||
Zu Beginn der Arbeit werden im \autoref{ch:basics} die Struktur und der grundsätzliche Aufbau der Anwendung
|
||||
Zu Beginn der Arbeit werden in \autoref{ch:basics} die Struktur und der grundsätzliche Aufbau der Anwendung
|
||||
erklärt. Hierbei wird aufgezeigt an welchen Stellen es immer wieder zu Unstimmigkeiten kommen kann und wie diese zu
|
||||
überprüfen sind.
|
||||
|
||||
Nachfolgend werden im \autoref{ch:concept} die Konzepte vorgestellt, die die Stellen ermitteln, die eine schlechte
|
||||
Nachfolgend werden in \autoref{ch:concept} die Konzepte vorgestellt, die die Stellen ermitteln, welche eine schlechte
|
||||
Performance aufweisen und optimiert werden sollen.
|
||||
Hierzu gehören zum einen die Einstellungen der verwendeten Software, und zum anderen der Aufbau und die verwendeten
|
||||
Techniken in der Anwendung. Diese Techniken werden im weiteren Verlauf nochmal überprüft, ob eine alternative Lösung
|
||||
einen performantere Umsetzung bringen kann.
|
||||
|
||||
Bei den Performance"=Untersuchungen im \autoref{ch:performance-checking} werden nun die Konzepte angewandt, um
|
||||
Bei den Performance"=Untersuchungen in \autoref{ch:performance-checking} werden nun die Konzepte angewandt, um
|
||||
die Umgebung selbst zu untersuchen und die dort bekannten Probleme zu ermitteln. Diese werden direkt bewertet, unter den
|
||||
Gesichtspunkten, ob eine Optimierung an dieser Stelle sinnvoll ist oder ob der Arbeitsaufwand dafür zu aufwendig ist.
|
||||
Zusätzlich werden noch die Vorbereitungen und die angepassten Konfigurationen für die nachfolgenden
|
||||
Performance"=Untersuchungen der Anwendung aufzeigt.
|
||||
|
||||
Zuerst wird im \autoref{ch:performance-investigation-application} die Ausgangsmessung durchgeführt, hierbei werden
|
||||
Zuerst wird in \autoref{ch:performance-investigation-application} die Ausgangsmessung durchgeführt, hierbei werden
|
||||
alle bekannten Caches deaktiviert und eine Messung durchgeführt.
|
||||
Dann werden Schicht für Schicht die Optimierungsmöglichkeiten aufgezeigt, umgesetzt und erneut gemessen. Diese Messung
|
||||
wird mit der Ausgangsmessung verglichen und bewertet.
|
||||
|
||||
Nach der Optimierung kommt nun die Evaluierung im \autoref{ch:evaluation}. Hier werden die verschiedenen Optimierungen
|
||||
Nach der Optimierung kommt nun die Evaluierung in \autoref{ch:evaluation}. Hier werden die verschiedenen Optimierungen
|
||||
begutachtet, in welchem Anwendungsfall die gewünschte Verbesserung in der Performance umgesetzt werden kann und welche
|
||||
für den vorliegenden Fall in der Praxis umsetzbar ist.
|
||||
|
||||
\todo{verena}
|
||||
Zum Abschluss im \autoref{ch:summary_and_outlook} \texthl{werden alle Optimierungen zusammengefasst und eine Abwägung}
|
||||
Zum Abschluss in \autoref{ch:summary_and_outlook} werden alle Optimierungen zusammengefasst und eine Abwägung
|
||||
getroffen, unter welchen Gesichtspunkten die Anpassungen eine sinnvolle Optimierung darstellen. Zusätzlich wird
|
||||
beschrieben wie ein weiteres Vorgehen durchgeführt werden kann.
|
||||
|
|
|
@ -8,11 +8,10 @@ dass jeder Wechsel einer Seite oder eine Suchanfrage als Web"=Request an den Ser
|
|||
geht durch mehrere Schichten des Server"=System bis die Antwort an den Client zurückgesendet wird, wie in
|
||||
\autoref{fig:webrequest} dargestellt.
|
||||
|
||||
\todo{die rede sein????}
|
||||
Es wird ab hier immer von einem \textit{Glassfish}"=Server die rede sein. In der Praxis wird ein \textit{Payara}"=Server
|
||||
Es wird ab hier von einem \textit{Glassfish}"=Server die Rede sein. In der Praxis wird ein \textit{Payara}"=Server
|
||||
verwendet. Der \textit{Glassfish}"=Server ist die Referenz"=Implementierung von Oracle, welche für Entwickler
|
||||
bereitgestellt wird und die neuen Features unterstützt. Der \textit{Payara}"=Server ist aus dessen Quellcode entstanden
|
||||
und ist für Produktivumgebungen gedacht, da dieser mit regelmäßigen Aktualisierungen versorgt wird. In dem weiteren Text
|
||||
bereitgestellt wird und neue Features unterstützt. Der \textit{Payara}"=Server ist aus dessen Quellcode entstanden
|
||||
und ist für Produktivumgebungen gedacht, da dieser mit regelmäßigen Aktualisierungen versorgt wird. Im folgenden Text
|
||||
wird der Begriff \textit{Glassfish} verwendet.
|
||||
|
||||
Angefangen bei der Anfrage die über den Webbrowser an den Server gestellt wird und vom \textit{Glassfish}"=Server
|
||||
|
@ -25,9 +24,9 @@ Hier wird nun geprüft, ob die Daten aus dem \textit{OpenJPA Cache} direkt ermit
|
|||
an das unterlagerte Datenbankmanagementsystem \textit{PostgreSQL} weitergeleitet werden muss. Die ermittelten Daten vom
|
||||
DBMS werden bei Bedarf im \textit{OpenJPA Cache} aktualisiert.
|
||||
|
||||
Das \textit{PostgreSQL} besteht aus mehreren Teilen die ineinander greifen um die Anfragen zu bearbeiten. Dabei
|
||||
sind die \textit{Memory Buffers} notwendig um den Zugriff auf die Festplatte zu reduzieren um die Bearbeitungszeit
|
||||
zu verringern. Um Anfragen die den Zugriff auf die Festplatte benötigen effizienter zu gestalten, bereiten die
|
||||
Das \textit{PostgreSQL} besteht aus mehreren Teilen die ineinander greifen, um die Anfragen zu bearbeiten. Dabei
|
||||
sind die \textit{Memory Buffers} notwendig, um den Zugriff auf die Festplatte zu reduzieren und die Bearbeitungszeit
|
||||
zu verringern. Um Anfragen, die den Zugriff auf die Festplatte benötigen effizienter zu gestalten, bereiten die
|
||||
\textit{Services} die Datenstrukturen auf.
|
||||
|
||||
\begin{figure}[!ht]
|
||||
|
@ -75,7 +74,7 @@ zu verringern. Um Anfragen die den Zugriff auf die Festplatte benötigen effizie
|
|||
In den Java"=EE"=Anwendungen wird der \textit{Persistenzkontext} für die Anfragen vom \textit{Application"=Server}
|
||||
bereitgestellt. Hierfür werden \textit{Application"=Server} wie \textit{GlassFish} genutzt, um die Verwendung eines Pools
|
||||
von Datenbankverbindungen zu definieren \citep[68]{MüllerWehr2012}. Dadurch kann die Anzahl der Verbindungen geringer
|
||||
gehalten werden als die Anzahl der Benutzer die an der Anwendung arbeiten. Zusätzlich werden die Transaktionen über
|
||||
gehalten werden als die Anzahl der Benutzer, die an der Anwendung arbeiten. Zusätzlich werden die Transaktionen über
|
||||
\textit{\ac{SFSB}} gehandhabt, welche automatisch vor dem Aufruf erzeugt und danach wieder gelöscht
|
||||
werden. Dies birgt allerdings den Nachteil, dass der \textit{Persistenzkontext} sehr groß werden kann, wenn viele
|
||||
Entities in den \textit{Persistenzkontext} geladen werden. Da dies häufig zu Speicher"~ und damit Performance"=Problemen
|
||||
|
@ -90,7 +89,7 @@ Objekte einen von vier Zuständen ein \citep[57]{MüllerWehr2012}. Im Zustand \t
|
|||
aber noch nicht in den Cache überführt worden. Wenn diese in den Cache überführt worden sind, nehmen sie den Zustand
|
||||
\texttt{Verwaltet} ein. Ist das Objekt aus dem Cache und der Datenbank entfernt worden, nimmt es den Zustand
|
||||
\texttt{Gelöscht} an. \texttt{Losgelöst} ist der letzte Zustand, bei dem das Objekt aus dem Cache entfernt worden ist,
|
||||
aber nicht aus der Datenbank.
|
||||
aber noch in der Datenbank verbleibt.
|
||||
|
||||
Eine Menge von Objekten wird als \textit{Persistenzkontext} bezeichnet. Solange die Objekte dem
|
||||
\textit{Persistenzkontext} zugeordnet sind, also den Zustand \texttt{Verwaltet} besitzen, werden diese auf Änderungen
|
||||
|
@ -100,16 +99,15 @@ Eine Menge von Objekten wird als \textit{Persistenzkontext} bezeichnet. Solange
|
|||
\section{Glassfish - OpenJPA Cache}
|
||||
\label{sec:basics:ojpac}
|
||||
|
||||
\todo{... die Verwendung spricht... - das spricht umformen}
|
||||
Zusätzlich kann im \textit{JPA} ebenfalls noch der \textit{Second Level Cache} (L2-Cache) aktiviert werden. Dieser steht
|
||||
jedem \textit{Persistenzkontext} zur Verfügung und kann dadurch die Anzahl der Datenbankzugriffe deutlich reduzieren,
|
||||
was bei langsamen Datenbank"=Anbindungen zu hohen Performance"=Gewinnen führen kann \citep[171]{MüllerWehr2012}.
|
||||
\texthl{Zu Beachten ist, dass die Daten im \textit{Second Level Cache} explizit über die Änderungen informiert werden
|
||||
müssen, weil sonst beim nächsten Aufruf veraltete Werte geliefert werden.} Ebenfalls benötigt ein Cache einen höheren Bedarf
|
||||
Zu Beachten ist, dass die Daten im \textit{Second Level Cache} explizit über die Änderungen informiert werden
|
||||
müssen, um zu verhindern, dass bei einem nachfolgenden Aufruf veraltete Werte zurückgegeben werden. Ebenfalls benötigt ein Cache einen höheren Bedarf
|
||||
an Arbeitsspeicher, in dem die Daten parallel zur Datenbank bereitgestellt werden, daher ist die Benutzung nur
|
||||
problemlos bei Entities möglich, auf welche meist lesend zugegriffen wird.
|
||||
|
||||
In der OpenJPA"=Erweiterung für den L2-Cache, wird in \textit{Objekt"=Cache} (in OpenJPA als \textit{DataCache}
|
||||
In der OpenJPA"=Erweiterung für den L2-Cache wird in \textit{Objekt"=Cache} (in OpenJPA als \textit{DataCache}
|
||||
bezeichnet) und \textit{Query"=Cache} unterschieden. Über die Funktionen \texttt{find()} und \texttt{refresh()} oder einer Query
|
||||
werden die geladenen Entities in den Cache gebracht. Davon ausgenommen sind \textit{Large Result Sets} (Abfragen die
|
||||
nicht alle Daten auf einmal laden), \texttt{Extent}"=Technologien und Queries, die einzelne Attribute von Entities
|
||||
|
@ -131,11 +129,11 @@ die Einstellungen an den Entities angepasst werden \citep{IbmOpenJPACaching2023}
|
|||
\label{sec:basics:memorybuffers}
|
||||
|
||||
Die Speicherverwaltung des PostgreSQL"=Servers muss für Produktivsysteme angepasst werden \citep[34-38]{Eisentraut2013}.
|
||||
Hierunter fallen die \texttt{shared\_buffers} die bei circa 10 bis 25 Prozent des verfügbaren Arbeitsspeichers liegen
|
||||
Hierunter fallen die \texttt{shared\_buffers}, die bei circa 10 bis 25 Prozent des verfügbaren Arbeitsspeichers liegen
|
||||
sollten. Mit dieser Einstellung wird das häufige Schreiben des Buffers durch Änderungen von Daten und Indexen auf die
|
||||
Festplatte reduziert.
|
||||
|
||||
Die Einstellung \texttt{temp\_buffers} definiert wie groß der Speicher für temporäre Tabellen pro
|
||||
Die Einstellung \texttt{temp\_buffers} definiert, wie groß der Speicher für temporäre Tabellen pro
|
||||
Verbindung maximal werden darf und sollte ebenfalls überprüft werden. Ein zu kleiner Wert bei großen temporären Tabellen
|
||||
führt zu einem signifikanten Leistungseinbruch, wenn die Tabellen nicht im Hauptspeicher, sondern in einer Datei
|
||||
ausgelagert werden.
|
||||
|
@ -156,7 +154,7 @@ durchgeführt werden, damit die Performance des Systems durch die Änderungen de
|
|||
\citep[75]{Eisentraut2013}. Hierfür gibt es den \texttt{VACUUM}"=Befehl, welcher entweder per Hand oder automatisch durch
|
||||
das Datenbanksystem ausgeführt werden soll. Für die automatische Ausführung kann der maximal verwendete Speicher über
|
||||
die Einstellung \texttt{autovacuum\_work\_mem} gesondert definiert werden \citep{PostgresPro:Chap20.4:2023}.
|
||||
Neben dem Aufräumen durch \texttt{VACUUM}, sollten auch die Planerstatistiken mit \texttt{ANALYZE}
|
||||
Neben dem Aufräumen durch \texttt{VACUUM} sollten auch die Planerstatistiken mit \texttt{ANALYZE}
|
||||
\citep[83]{Eisentraut2013} aktuell gehalten werden, damit die Anfragen durch den Planer richtig optimiert werden können.
|
||||
Für beide Wartungsaufgaben gibt es den Autovacuum"=Dienst, dieser sollte aktiv und richtig konfiguriert sein.
|
||||
|
||||
|
@ -167,16 +165,16 @@ ermittelt werden.
|
|||
\section{PostgreSQL - Abfragen}
|
||||
\label{sec:basics:queries}
|
||||
|
||||
Für weitere Optimierungen werden anschließend die Anfragen einzeln überprüft. Hierfür ist es sinnvoll die
|
||||
Für weitere Optimierungen werden anschließend die Anfragen einzeln überprüft. Hierfür ist es sinnvoll, die
|
||||
Ausführungspläne der Abfrage zu analysieren \citep[252]{Eisentraut2013}, die verschiedenen Plantypen und ihre Kosten zu
|
||||
kennen, sowie die angegeben Werte für die Plankosten zu verstehen \citep[24-30]{Dombrovskaya2021}.
|
||||
kennen sowie die angegeben Werte für die Plankosten zu verstehen \citep[24-30]{Dombrovskaya2021}.
|
||||
Besonderes Augenmerk gilt dem Vergleichen des tatsächlich ausgeführten mit dem ursprünglichen Plan
|
||||
\citep[254]{Eisentraut2013}. Eine der wichtigsten Kennzeichen hierbei ist, ob die Zeilenschätzung akkurat war.
|
||||
Größere Abweichungen weißen häufig auf veraltete Statistiken hin.
|
||||
\citep[254]{Eisentraut2013}. Eine \todo{eine oder eines?} der wichtigsten Kennzeichen hierbei ist, ob die Zeilenschätzung akkurat war.
|
||||
Größere Abweichungen weisen häufig auf veraltete Statistiken hin.
|
||||
|
||||
Um die Abfragen selbst zu optimieren, gibt es ein Vorgehen über mehrere Schritte \citep[304-308]{Dombrovskaya2021}.
|
||||
Zuerst wird unterschieden, ob es sich um eine \textit{Kurze} oder eine \textit{Lange} Abfrage handelt. Im Falle einer
|
||||
\textit{Kurzen} Abfrage, werden zuerst die Abfragekriterien überprüft. Sollte dies zu keiner Verbesserung führen,
|
||||
\textit{Kurzen} Abfrage werden zuerst die Abfragekriterien überprüft. Sollte dies zu keiner Verbesserung führen,
|
||||
werden die Indexe geprüft. Ist dies ebenso erfolglos, wird die Abfrage nochmals genauer analysiert und so
|
||||
umgestellt, dass die restriktivste Einschränkung zuerst zutrifft.
|
||||
Bei einer \textit{Langen} Abfrage soll überprüft werden, ob es sinnvoll ist, das Ergebnis in einer Tabelle zu
|
||||
|
@ -189,8 +187,8 @@ werden können, um die Abfragemenge zu verringern.
|
|||
Bei \textit{Langen} Abfragen ist die Abhandlung >>Optimizing Iceberg Queries with Complex Joins<<
|
||||
\citep{10.1145/3035918.3064053} ein zusätzlicher Ratgeber, um die Performance zu steigern.
|
||||
|
||||
Des Weiteren können über das Modul \texttt{pg\_stat\_statements} Statistiken der Aufrufe die an den Server gestellt
|
||||
Des Weiteren können über das Modul \texttt{pg\_stat\_statements} Statistiken der Aufrufe, die an den Server gestellt
|
||||
wurden, ermittelt werden \citep{PostgresF27:2023}. Hierbei können die am häufigsten Aufgerufenen und die Anfragen mit
|
||||
der längsten Ausführungszeit ermittelt werden. Ohne zu dem zusätzlichen Modul, können die Statistiken über die
|
||||
der längsten Ausführungszeit ermittelt werden. Ohne das zusätzliche Modul können die Statistiken über die
|
||||
Software \textit{pgBadger} erstellt werden. Dafür muss zusätzlich noch die Konfiguration des \textit{PostgreSQL}
|
||||
angepasst werden.
|
||||
|
|
|
@ -19,15 +19,15 @@ Hierunter fallen die Einstellungen für die \texttt{shared\_buffers}, der bei ei
|
|||
circa 25\% des Arbeitsspeicher besitzen sollte \cite{PostgresC20.4:2024}.
|
||||
|
||||
Bei der Einstellung \texttt{temp\_buffers} geht es um den Zwischenspeicher für jede Verbindung, die bei der Verwendung
|
||||
von temporären Tabellen verwendet wird. Dieser Wert sollte auf dem Standardwert von 8 MB belassen werden, lediglich bei
|
||||
der Verwendung von großen temporären Tabellen verändert werden.
|
||||
von temporären Tabellen verwendet wird. Dieser Wert sollte auf dem Standardwert von 8 MB belassen werden und lediglich
|
||||
bei der Verwendung von großen temporären Tabellen verändert werden.
|
||||
|
||||
Der Speicher, der für eine Abfrage verwendet werden darf, wird über die Konfiguration \texttt{work\_mem} gesteuert.
|
||||
Wenn der Speicher zu gering wird, werden die Zwischenergebnisse in temporäre Dateien ausgelagert. Der empfohlene Wert
|
||||
berechnet sich aus \texttt{shared\_buffers} dividiert durch \texttt{max\_connections} \citep{ConfigTo12:online}.
|
||||
Sollte die Berechnung außerhalb der Grenzwerte von 1 MB und 256 MB liegen, ist der jeweilige Grenzwert zu verwenden.
|
||||
Um zu ermitteln, ob die Konfiguration richtig ist, muss im PostgreSQL die Einstellung \texttt{log\_temp\_files} auf 0
|
||||
gesetzt werden. Mit dieser kann ermittelt, ob temporäre Dateien verwendet werden und deren Größe. Bei vielen kleineren
|
||||
gesetzt werden. Mit dieser kann ermittelt, ob temporäre Dateien verwendet werden sowie deren Größe. Bei vielen kleineren
|
||||
Dateien sollte der Grenzwert erhöht werden. Bei wenigen großen Dateien ist es ist sinnvoll den Wert so zu belassen.
|
||||
|
||||
Für die Wartungsaufgaben wie VACUUM oder dem Erstellen von Indexen wird die Begrenzung über die Einstellung
|
||||
|
@ -38,14 +38,14 @@ Nachfolgend wird mit dem Systemtools, wie den Konsolenanwendungen \textit{htop}
|
|||
überprüft. Hierbei ist die CPU"=Leistung, der aktuell genutzte Arbeitsspeicher, sowie die Zugriffe auf die Festplatte
|
||||
die wichtigen Faktoren zur Bewertung.
|
||||
|
||||
Die CPU"=Leistung sollte im Schnitt 70\% nicht überschreiten, für kurze Spitzen wäre dies zulässig. Da sonst der
|
||||
Server an seiner Leistungsgrenze arbeitet und dadurch es nicht mehr schafft die gestellten Anfragen schnell genug
|
||||
abzuarbeiten.
|
||||
Die CPU"=Leistung sollte im Schnitt 70\% nicht überschreiten, für kurze Spitzen wäre dies zulässig. Um zu verhindern, dass der
|
||||
Server an seiner Leistungsgrenze arbeitet und es dadurch nicht mehr schafft, die gestellten Anfragen schnell genug
|
||||
abzuarbeiten.\todo{Satz überarbeiten}
|
||||
|
||||
Da unter Linux der Arbeitsspeicher nicht mehr direkt freigegeben wird, ist hier die Page"=Datei der wichtigere Indikator.
|
||||
Wenn dieses in Verwendung ist, dann benötigen die aktuell laufenden Programme mehr Arbeitsspeicher als vorhanden ist,
|
||||
wodurch der aktuell nicht verwendete in die Page"=Datei ausgelagert wird. Hierdurch erhöhen sich die Zugriffszeiten auf
|
||||
diese Elemente drastisch.
|
||||
wodurch der aktuell nicht verwendete in die Page"=Datei ausgelagert wird. Zu beachten ist hierbei allerdings, dass sich
|
||||
die Zugriffszeiten auf die Elemente drastisch erhöhen.
|
||||
|
||||
Die Zugriffsgeschwindigkeit, die Zugriffszeit sowie die Warteschlange an der Festplatte zeigt deren Belastungsgrenze auf.
|
||||
In diesem Fall kann es mehrere Faktoren geben. Zum einem führt das Paging des Arbeitsspeicher zu erhöhten Zugriffen.
|
||||
|
@ -55,7 +55,7 @@ zwischengespeichert werden kann und daher diese Daten immer wieder direkt von de
|
|||
\section{Untersuchung der Anwendung}
|
||||
\label{sec:concept:softwarestructure}
|
||||
|
||||
Bei der Performance"=Untersuchung der Anwendung, wird sich im ersten Schritt auf die Dokumentenliste beschränkt. Anhand
|
||||
Bei der Performance"=Untersuchung der Anwendung wird sich im ersten Schritt auf die Dokumentenliste beschränkt. Anhand
|
||||
dieser können die Optimierungen getestet und überprüft werden. Im Nachgang können die daraus gewonnenen Kenntnisse auf
|
||||
die anderen Abfragen übertragen werden.
|
||||
|
||||
|
@ -72,7 +72,7 @@ Ort aufgehalten haben.
|
|||
|
||||
Da die Daten in der 3. Normalform in der Datenbank gespeichert werden, sind einige Relationen für die Abfragen
|
||||
notwendig. Dies wird durch die generische Abfrage in \autoref{lst:documentlist} gezeigt. Zusätzlich wird für jedes
|
||||
dargestellte Dokument eine zusätzliche Abfrage durchgeführt, die in \autoref{lst:documentlist_sub} zeigt, dass auch hier
|
||||
dargestellte Dokument eine zusätzliche Abfrage durchgeführt, wie in \autoref{lst:documentlist_sub} zeigt, dass auch hier
|
||||
weitere Relationen notwendig sind.
|
||||
|
||||
\includecode[SQL]{chapters/thesis/chapter03_documentlist.sql}{lst:documentlist}{Generische Abfrage der Dokumentenliste}
|
||||
|
@ -82,13 +82,13 @@ Nach aktuellem Stand beinhaltet die Datenbank circa 5400 Briefe, für die jeweil
|
|||
gespeichert werden. Diese Graphik-Dateien werden im TIFF-Format abgespeichert und benötigen zwischen 1 und 80 MB
|
||||
Speicherplatz. Dadurch kommt die Datenbank aktuell auf circa 3,8 GB.
|
||||
|
||||
Wie im \autoref{ch:basics} dargestellt, besteht die eigentliche Anwendung aus mehreren Schichten. Die
|
||||
PostgreSQL"=Schicht wurde schon im vorherigen Kapitel betrachtet. Daher gehen wir nun weiter nach oben in den Schichten
|
||||
vom Glassfish"=Server.
|
||||
Wie in \autoref{ch:basics} dargestellt, besteht die eigentliche Anwendung aus mehreren Schichten. Die
|
||||
PostgreSQL"=Schicht wurde schon im vorherigen Kapitel betrachtet. Daher werden nun die weiteren Schichten des
|
||||
Glassfish"=Server in aufsteigender Reihenfolge betrachtet.
|
||||
|
||||
Die OpenJPA Cache Schicht wird nun einzeln untersucht. Hierfür werden die zuerst die Cache"=Statistik für Object"=Cache
|
||||
Die OpenJPA Cache Schicht wird nun einzeln untersucht. Hierfür werden zuerst die Cache"=Statistik für Object"=Cache
|
||||
und Query"=Cache aktiviert \citep[315]{MüllerWehr2012}. Die somit erfassten Werte, werden über eine Webseite
|
||||
bereitgestellt, um die Daten Live vom Server verfolgen zu können. Zusätzlich werden die Webseite über ein Script
|
||||
bereitgestellt, um die Daten Live vom Server verfolgen zu können. Zusätzlich wird die Webseite über ein Script
|
||||
aufgerufen und die Aufrufzeiten sowie andere externe Statistiken darüber erstellt und gespeichert.
|
||||
|
||||
In der \ac{JPA} Schicht sind die Anzahl der Entitäten im Persistence Context zu beobachten. Die Anzahl der verschiedenen
|
||||
|
@ -112,27 +112,27 @@ Die Schicht \ac{EJB} besitzt keine Möglichkeit um eine sinnvolle Messung durchz
|
|||
direkte Messungen eingefügt. Hier werden nur die externen Statistiken durch das Skript verwendet, um zu prüfen in
|
||||
welchen Umfang die Umstellungen eine Veränderung im Verhalten der Webseite bewirken.
|
||||
|
||||
Bei den \ac{JSF} wird eine Zeitmessung eingefügt. Um sich in die Verarbeitung der Seiten einzuhängen, wird eine
|
||||
\textit{Factory} benötigt. In dieser werden die Zeiten zum Ermitteln der Daten, das Zusammensetzen und das Rendern
|
||||
Bei den \ac{JSF} wird eine Zeitmessung eingefügt. Um sich in die Verarbeitung der Seiten \todo{was ist an einzuhängen falsch?, das sich muss weg} einzuhängen, wird eine
|
||||
\textit{Factory} benötigt. \todo{Umstellen weil 2x Ermitteln} In dieser werden die Zeiten zum Ermitteln der Daten, das Zusammensetzen und das Rendern
|
||||
der Sicht ermittelt. Die Zeiten werden in die Log"=Datei des \textit{Glassfish}"=Servers hinterlegt und durch das
|
||||
Skript ausgewertet. Somit ist es relativ leicht aufzuzeigen, an welcher Stelle der größte Teil der Verzögerung auftritt.
|
||||
Skript ausgewertet. Somit ist es relativ leicht aufzuzeigen, an welcher Stelle die größte Verzögerung auftritt.
|
||||
|
||||
Die Abfragen werden ebenfalls untersucht und mit verschiedenen Methoden optimiert. Hierfür werden zum einen auf native
|
||||
SQL"=Anfragen umgestellt und die Ausführungszeiten überprüft. Ebenfalls werden die Abfragen durch Criteria API erzeugt
|
||||
SQL"=Anfragen umgestellt und die Ausführungszeiten überprüft. Zum anderen werden die Abfragen durch Criteria API erzeugt
|
||||
und dessen Ausführungszeit ermittelt.
|
||||
|
||||
Zusätzlich werden im SQL-Server Optimierungen vorgenommen, darunter zählen die \textit{Materialized View}, welche eine
|
||||
erweiterte Sicht ist. Neben der Abfrage der Daten beinhalteten diese auch noch vorberechneten Daten der Abfrage, womit
|
||||
erweiterte Sicht ist. Neben der Abfrage der Daten beinhalteten diese auch vorberechneten Daten der Abfrage, womit
|
||||
diese viel schneller abgefragt werden können. Zusätzlich werden die cached queries überprüft, ob diese eine Verbesserung
|
||||
der Performance und der Abfragedauern verkürzen können.
|
||||
|
||||
Damit die Messungen nachvollziehbar bleiben, werden die Testaufrufe durch ein Bash-Script automatisiert gerufen.
|
||||
Wichtig hierbei ist, dass die Webseite immer vollständig gerendert vom Server an den Client übertragen wird.
|
||||
Somit kann die clientseitige Performance ignoriert werden, da alles Daten direkt in dem einen Aufruf bereitgestellt
|
||||
wird. In dem Skript werden zum einen die Laufzeiten der Webanfragen ermittelt und die kürzeste, die längste und die
|
||||
Somit kann die clientseitige Performance ignoriert werden, da alle Daten direkt in diesem Aufruf bereitgestellt
|
||||
wird. In dem Skript werden zum einen die Laufzeiten der Webanfragen ermittelt,\todo{wie anders schreiben, zum einen - zum anderen} zum anderen die kürzeste, die längste und die
|
||||
durchschnittliche Laufzeit ermittelt. Auf Grund der Speicherprobleme, werden auch die Speicherbenutzung des
|
||||
\textit{Glassfish}"=Servers vor und nach den Aufrufen ermittelt. Zum Schluss werden noch die Log"=Dateien des
|
||||
\textit{PostgreSQL}"=Servers über das Tool \textit{pgBadger} analysiert und als Bericht aufbereitet.
|
||||
|
||||
Um die Netzwerklatenz ignorieren zu können, wird das Skript auf dem gleichen Computer aufgerufen, auf dem der Webserver
|
||||
gestartet wurde. Das zugehörige Script ist im \autoref{ap:timing} zu finden.
|
||||
gestartet wurde. Das zugehörige Script ist in \autoref{ap:timing} zu finden.
|
||||
|
|
|
@ -50,7 +50,7 @@ ausgewertet werden.
|
|||
Zusätzlich wird noch eine Implementierung der zugehörigen Factory"=Klasse \texttt{ViewDeclarationLanguageFactory}
|
||||
benötigt. Durch diese Factory"=Klasse wird der eigentlichen Wrapper mit der Performance-Messung in die Bearbeitungsschicht
|
||||
eingehängt. Diese Implementierung wird dann noch in der \texttt{faces-config.xml} eingetragen, wie das in
|
||||
\autoref{lst:activate-factory} gezeigt wird, damit die Factory durch das System aufgerufen wird.
|
||||
\autoref{lst:activate-factory} aufgezeigt wird, damit die Factory durch das System aufgerufen wird.
|
||||
|
||||
\begin{lstlisting}[language=xml,caption={Einbindung Factory},label=lst:activate-factory]
|
||||
<factory>
|
||||
|
@ -60,9 +60,9 @@ eingehängt. Diese Implementierung wird dann noch in der \texttt{faces-config.xm
|
|||
</factor>
|
||||
\end{lstlisting}
|
||||
|
||||
Der Quellcode der Klassen ist im \autoref{ap:jsf_performance_measure} zu finden.
|
||||
Der Quellcode der Klassen ist in \autoref{ap:jsf_performance_measure} zu finden.
|
||||
|
||||
Um die Abfragen im \textit{PostgreSQL} untersuchen zu können, ist es am leichtesten, wenn man die Konfiguration so
|
||||
Um die Abfragen im \textit{PostgreSQL} untersuchen zu können, ist es am einfachsten, wenn man die Konfiguration so
|
||||
anpasst, dass alle Abfragen mit entsprechenden Zeitmessungen in die Log"=Datei ausgegeben werden.
|
||||
Über die Einstellungen in \autoref{lst:postgresql_logfile} wird die Datei und das Format der Ausgabe definiert.
|
||||
|
||||
|
@ -104,7 +104,7 @@ log_timezone = 'Europe/Berlin'
|
|||
|
||||
Das Untersuchen der protokollierten Abfragen auf Performance Optimierungen ist ein weiterer Bestandteil dieser Arbeit.
|
||||
Das Schlüsselwort \texttt{EXPLAIN} ist im PostgreSQL vorhanden, um den Abfrageplan einer Abfrage zu ermitteln und
|
||||
darzustellen, um diesen zu untersuchen. Der Abfrageplan ist als Baum dargestellt, bei welchem die Knoten die
|
||||
darzustellen, um diese anschließend zu untersuchen. Der Abfrageplan ist als Baum dargestellt, bei welchem die Knoten die
|
||||
unterschiedlichen Zugriffsarten darstellen. Die Verbindung der Knoten und der Aufbau zeigt die Operationen, wie
|
||||
etwa Joins, Aggregierung und Sortierung, und die Reihenfolgen der Abarbeitung. Zusätzlich sind auch Zwischenschritte,
|
||||
wie Zwischenspeicherungen ersichtlich. Zu jeder Operation gibt es neben dem Typ noch zusätzliche Informationen, wie
|
||||
|
@ -122,25 +122,24 @@ EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SUMMARY)
|
|||
select * from document;
|
||||
\end{lstlisting}
|
||||
|
||||
\todo{bei seq scan ... nochmal neu überlegen + Satz mit seigenden kosten fehlt}
|
||||
Die zwei bekanntesten Knotentypen sind \texttt{Seq Scan} und \texttt{Index Scan}. \texthl{Wenn eine Tabelle Zeile für Zeile
|
||||
gelesen wird,} zeigt der Abfrageplan einen \texttt{Seq Scan}"=Knoten an. Hierbei entsteht, unabhängig davon ob eine
|
||||
Die zwei bekanntesten Knotentypen sind \texttt{Seq Scan} und \texttt{Index Scan}. Wenn eine Tabelle Zeile für Zeile
|
||||
gelesen wird, zeigt der Abfrageplan einen \texttt{Seq Scan}"=Knoten an. Hierbei entsteht, unabhängig davon ob eine
|
||||
Bedingung zum filtern vorhanden ist, eine unsortierte Liste dessen Startkosten entsprechend niedrig sind. Je weiter die
|
||||
Liste durchlaufen wird, desto höher steigen die notwendigen Kosten. Die kostengünstigere Alternative ist der
|
||||
\texttt{Index Scan}, bei dem der Index nach den Kriterien durchsucht wird, was meist durch den Aufbau des Index als
|
||||
BTree (Multi"=Way Balanced Tree) rapide geht.
|
||||
|
||||
Eine weitere Optimierungsmöglichkeit ist die Verwendung von Indexe. Diese sind aber mit Bedacht zu wählen, da bei
|
||||
Eine weitere Optimierungsmöglichkeit ist die Verwendung von Indexen. Diese sind aber mit Bedacht zu wählen, da bei
|
||||
mehreren Indexen die sehr ähnlich sind, nicht immer der gewünschte Index bei der Abfrage verwendet wird. Auch bedeutet
|
||||
ein Index bei jeder Änderung der Daten zusätzliche Arbeit, da dieser entsprechend mit gepflegt werden muss und auch
|
||||
ein Index bei jeder Änderung der Daten zusätzliche Arbeit, da dieser entsprechend mit gepflegt werden muss und ebenso
|
||||
dessen Statistik muss regelmässig aktualisiert werden. Ebenfalls ist die Reihenfolge der Spalte in einem
|
||||
zusammengesetzten Index von Bedeutung. Als Grundlage sollte hier mit der Spalte gestartet werden, welche die größte
|
||||
Einschränkung durchführt. Zusätzlich muss die Art des Index definiert werden, welche davon abhängig ist, mit welcher
|
||||
Vergleichsoperation auf die Tabellenspalte zugegriffen wird.
|
||||
|
||||
Um größere und aufwendigere Abfragen zu optimieren, bietet der PostgreSQL noch die Möglichkeit von
|
||||
\textit{Materialized View}. Diese sind sehr ähnlich zu den Sichten, zusätzlich werden die Ergebnisse in einer
|
||||
tabellenähnlichen Form abgespeichert. Somit sind die Zugriff auf diese Daten häufig performanter als die eigentliche Abfrage.
|
||||
\textit{Materialized View}. Diese sind sehr ähnlich zu den Sichten, zusätzlich werden aber die Ergebnisse in einer
|
||||
tabellenähnlichen Form abgespeichert, somit sind die Zugriff auf diese Daten häufig performanter als die eigentliche Abfrage.
|
||||
Daher muss abgewägt werden, ob die Performance-Verbesserung trotz der zusätzliche Aktualisierung des Datenbestandes
|
||||
als sinnvoll erachtet werden kann.
|
||||
|
||||
|
|
|
@ -25,14 +25,14 @@ Hälfte des verfügbaren Arbeitsspeichers des Computers ungenutzt.
|
|||
|
||||
Mit der Konfiguration \texttt{-Xmx} wird der maximal verwendbare Heap"=Speicher in der \ac{JVM} definiert.
|
||||
Dies zeigt direkt, dass es ein Problem in der Freigabe der Objekte gibt, da dass Erhöhen des verwendbaren
|
||||
Arbeitsspeicher das Problem nicht löst, sondern nur verschiebt.
|
||||
Arbeitsspeicher das Problem nicht löst, sondern nur verlagert.
|
||||
|
||||
Für alle nachfolgenden Messungen wird das Skript im \autoref{ap:calling_script} verwendet, welches die einzelnen
|
||||
Aufrufe steuert. Die Ergebnisse werden in eine Tabelle überführt, wie in \autoref{tbl:measure-without-cache}.
|
||||
Hierbei werden die Aufrufzeiten der Webseite aus dem Skript für die Zeitmessung mit Mindest"~, Durchschnitt"~ und
|
||||
Maximalzeit aufgenommen, hierbei ist eine kürzere Zeit besser. Zusätzlich wird die Anzahl der aufgerufenen SQL Abfragen
|
||||
ermittelt, auch hier gilt, dass weniger Aufrufe besser sind. Als letztes wird noch der verwendete Arbeitsspeicher
|
||||
vom \textit{Glassfish}"=Server vor und nach dem Aufruf ermittelt und die Differenz gebildet, hierbei sollte im besten
|
||||
ermittelt, auch hier gilt, je weniger Aufrufe desto besser. Als letztes wird noch der verwendete Arbeitsspeicher
|
||||
vom \textit{Glassfish}"=Server vor und nach dem Aufruf ermittelt und die Differenz gebildet, hierbei sollte im idealen
|
||||
Fall die Differenz bei 0 liegen. Dieser Aufbau gilt für alle weiteren Messungen. Zusätzlich werden noch die Laufzeiten
|
||||
der \ac{JSF} ermittelt und die durchschnittlichen Zeiten mit in der Tabelle dargestellt, und auch hier ist es besser,
|
||||
wenn die Zeiten kürzer sind.
|
||||
|
@ -74,7 +74,7 @@ Da die Abfragezeiten auf der Datenbank zu gering waren, um eine Verbesserung fes
|
|||
PostgreSQL und den Payara"=Server ein Docker"=Container erzeugt und diese limitiert. Die Konfiguration ist in
|
||||
\autoref{ap:docker_config} beschrieben.
|
||||
|
||||
Mit dem neuen Aufbau ergeben sich nun eine neue Messung. Für den Speicherbedarf wird nun nicht mehr der benutzte
|
||||
Mit dem neuen Aufbau ergibt sich eine neue Messung. Für den Speicherbedarf wird nun nicht mehr der benutzte
|
||||
Speicher der Anwendung beobachtet, sondern die Speichernutzung des Docker-Containers für den Payara-Server. Auch hier
|
||||
ist es besser, wenn es keine oder nur geringe Änderungen vor und nach dem Aufruf der Webseite gibt, ein steigender Wert
|
||||
zeigt an, dass der verwendete Speicher nicht sauber freigegeben werden kann.
|
||||
|
@ -84,9 +84,9 @@ Hierzu zählt die Hauptabfrage der Dokumenten"=-Tabelle, die Ermittlung des letz
|
|||
die Ermittlung der Adressen des Autors, die Ermittlung der Koautoren, die Ermittlung der Faksimile, sowie die Ermittlung
|
||||
der Anzahl aller vorhandenen Dokumente.
|
||||
|
||||
Zusätzlich wird die Zeit des Rendern der Sicht gemessen. Hierbei wird zum einen die komplette Zeit des Renderns
|
||||
ermittelt. Innerhalb des Rendern wird dann noch die Zeit gemessen, wie lange es benötigt, die Daten aus der Datenbank
|
||||
zu laden, und in die Java"=Objekte umzuformen.
|
||||
Zusätzlich wird die Zeit des Rendern der Sicht gemessen. Die erste Messung erfasst die komplette Laufzeit die fürs Rendern
|
||||
notwendig benötigt wird. Diese Zeit wird unterteilt in die Messungen für das Laden der Daten aus der Datenbank und das Erstellen
|
||||
der Java"=Objekte inklusive dem Befüllen mit den geladenen Daten.
|
||||
|
||||
\begin{table}[h]
|
||||
\centering
|
||||
|
@ -115,7 +115,7 @@ zu laden, und in die Java"=Objekte umzuformen.
|
|||
Die Cache"=Einstellung von OpenJPA werden über die zwei Einstellungen \texttt{openjpa.DataCache} und
|
||||
\texttt{openjpa.QueryCache} konfiguriert. Bei beiden Einstellungen kann zuerst einmal über ein einfaches Flag
|
||||
\textit{true} und \textit{false} entschieden werden ob der Cache aktiv ist. Zusätzlich kann über das Schlüsselwort
|
||||
\textit{CacheSize} die Anzahl der Elemente im Cache gesteuert werden. Wird diese Anzahl erreicht, dann werden zufällige
|
||||
\textit{CacheSize} die Anzahl der Elemente im Cache gesteuert werden. Wird diese Anzahl erreicht, werden zufällige
|
||||
Objekte aus dem Cache entfernt und in eine SoftReferenceMap übertragen. Bei der Berechnung der Anzahl der Elemente werden
|
||||
angeheftete Objekte nicht beachtet.
|
||||
|
||||
|
@ -206,7 +206,7 @@ die \textit{SoftReference} nicht das Problem für den steigenden Arbeitsspeicher
|
|||
\label{tbl:measure-ojpa-active-bigger-no-softref}
|
||||
\end{table}
|
||||
|
||||
Der Vergleich zeigt, dass der Cache eine gute Optimierung bringt, aber dies nur dann gut funktioniert, wenn immer
|
||||
Der Vergleich zeigt, dass der Cache eine gute Optimierung bringt, aber dies kann nur dann gut funktionieren, wenn immer
|
||||
wieder die gleichen Objekte ermittelt werden. Sobald die Anfragen im Wechsel gerufen werden oder einfach nur die Menge
|
||||
der Objekte den Cache übersteigt, fällt die Verbesserung geringer aus.
|
||||
|
||||
|
@ -244,13 +244,14 @@ mit \ac{JPQL} oder Criteria API abfragt wird.
|
|||
\section{Caching mit Ehcache}
|
||||
\label{sec:performance-investigation-application:caching-ehcache}
|
||||
|
||||
\todo{hier weiter machen!!!!}
|
||||
Der Ehcache ist ein L2"=Cache den man direkt in OpenJPA mit integrieren kann. Hierfür sind einige Punkte zu beachten.
|
||||
Zum einen muss die Reference auf das \textit{ehcache} und das \textit{ehcache"=openjpa} Packet hinzugefügt werden.
|
||||
Zum einen muss die Referenz auf das \textit{ehcache} und das \textit{ehcache"=openjpa} Paket hinzugefügt werden.
|
||||
Zusätzlich dazu sind die Konfiguration \textit{openjpa.""QueryCache}, \textit{openjpa.""DataCache} und
|
||||
\textit{openjpa.""DataCacheManager} auf \textit{ehcache} anzupassen. Anhand der Annotation \texttt{@DataCache} kann
|
||||
an jeder Klasse die Benennung des Caches sowie die Verwendung selbst gesteuert werden. Es wird für jede Klasse ein
|
||||
eigener Cache angelegt und der Name auf den vollen Klassennamen gesetzt. Die Verwendung ist für alle Klassen
|
||||
aktiviert und müssen explizit deaktiviert werden, wenn dies nicht gewünscht ist. Als letztes muss noch der
|
||||
aktiviert und muss explizit deaktiviert werden, wenn dies nicht gewünscht ist. Als letztes muss noch der
|
||||
Cache"=Manager aktiviert werden, dieser kann entweder durch Code programmiert werden oder über eine Konfiguration
|
||||
in der \textit{ehcache.xml}.
|
||||
|
||||
|
@ -258,7 +259,7 @@ Anhand der Auswertung von \ref{tbl:measure-ehcache-active} sieht man, dass der E
|
|||
Verbesserung aufbringt. Über die Performance"=Statistik"=Webseite kann beobachtet werden, dass bei gleichen Aufrufen
|
||||
der Webseite nur die Treffer in Cache steigen, aber die Misses nicht. Ebenfalls erhöht sich die Anzahl der Objekte
|
||||
im Cache nicht. Zusätzlich steigt in diesem Fall der Speicherverbrauch nur gering bis gar nicht. Des Weiteren zeigt sich,
|
||||
dass sich die Abfragezeiten in der Datenbank nur gering verkürzt wurden, aber die Laufzeit der Webseite sich stark
|
||||
dass die Abfragezeiten in der Datenbank nur gering verkürzt wurden, aber die Laufzeit der Webseite sich stark
|
||||
verbessert hat. Dies lässt auch hier den Schluss zu, dass die Erstellung der Objekte im OpenJPA die meiste Zeit
|
||||
benötigt.
|
||||
|
||||
|
@ -289,13 +290,13 @@ benötigt.
|
|||
\label{sec:performance-investigation-application:caching-ejb}
|
||||
|
||||
Die Cache"=Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Servers zu erreichen. Unter dem Punkt
|
||||
Configurations $\Rightarrow$ server"=config $\Rightarrow$ EJB Container werden zum einem die minimalen und maximalen
|
||||
Configurations $\Rightarrow$ server"=config $\Rightarrow$ EJB Container werden zum einen die minimalen und maximalen
|
||||
Größen des Pools definiert werden. Zum anderen wird an dieser Stelle die maximale Größe des Caches und die Größe der
|
||||
Erweiterung definiert.
|
||||
|
||||
Anhand der Auswertung der \autoref{tbl:measure-ejb-cache-active} ist ersichtlich, dass der \ac{EJB}"=Cache keine
|
||||
Auswirkung auf die Performance hat. Ebenso ist es ersichtlich, dass die Anzahl der Datenbankabfragen nicht reduziert
|
||||
wurden. Dies ist dadurch zu erklären, dass im \ac{EJB} die Provider gelagert werden, die über Dependency Injection
|
||||
wurde. Dies ist dadurch zu erklären, dass im \ac{EJB} die Provider gelagert werden, die über Dependency Injection
|
||||
den Controller bereitgestellt werden. Die Objekt selbst werden nicht im \ac{EJB}"=Cache hinterlegt.
|
||||
|
||||
% document, documentaddresseeperson, first/last, documentcoauthorperson, count und documentfacsimile
|
||||
|
@ -362,11 +363,11 @@ Messung aus \autoref{tbl:measure-without-cache} entspricht.
|
|||
Für die Optimierung wurden noch zusätzlich die Hints \texttt{openjpa.""hint.""OptimizeResultCount},
|
||||
\texttt{javax.""persistence.""query.""fetchSize} und \texttt{openjpa.""FetchPlan.""FetchBatchSize} gesetzt. Hierbei
|
||||
konnten je nach gesetzten Wert, keine relevanten Unterschiede festgestellt werden. Hierbei wurde der Wert auf zwei
|
||||
gesetzt, welcher viel zu gering ist. Als weiterer Test wurde der Wert auf angefragte Größte gestellt und auf den
|
||||
20"=fachen Wert der angefragten Größe.
|
||||
gesetzt, welcher viel zu gering ist. Als weiterer Test wurde der Wert auf die angefragte Größe und den
|
||||
20"=fachen Wert dieser Größe gestellt.
|
||||
|
||||
Ebenso bringt der Hint \texttt{openjpa.""FetchPlan.""ReadLockMode} auch keinen Unterschied bei der Geschwindigkeit.
|
||||
Hierbei ist erklärbar, das im Standard bei einer reinen Selektion eine Lesesperre aktiv sein muss.
|
||||
Dies ist dadurch erklärbar, dass im Standard bei einer reinen Selektion eine Lesesperre aktiv sein muss.
|
||||
Bei \texttt{openjpa.""FetchPlan.""Isolation} wird gesteuert, auf welche Sperren beim Laden geachtet wird. Damit könnte
|
||||
man lediglich Schreibsperren umgehen, und würde damit die Anfrage nicht mehr blockieren lassen, jedoch führt es unweigerlich
|
||||
zu sogenannten >>Dirty"=Reads<<, wodurch die Ausgabe verfälscht werden könnte. Daher ist diese Einstellung
|
||||
|
@ -378,10 +379,9 @@ Statement abgefragt. Mit \textit{join} wird definiert, dass abhängige Objekte d
|
|||
definiert sind, in der Abfrage über einen Join verknüpft und damit direkt mitgeladen werden. Bei reinen
|
||||
>>to-one<<"=Relation funktioniert das Rekursiv und spart sich damit einige einzelne Abfragen.
|
||||
Bei der Einstellung \textit{parallel} wird zwar für jede abhängige Objektdefinition eine Abfrage ausgeführt und
|
||||
\texthl{diese werden direkt auf die Hauptobjekte gefiltert und die Verknüpfung im} OpenJPA"=Framework durchgeführt.
|
||||
\todo{das wurde umgebaut}
|
||||
Somit muss in unserem Beispiel nicht für jedes Dokument eine einzelne Abfrage für die Koautoren durchgeführt werden,
|
||||
sondern es wird nur eine Abfrage abgesetzt für alle Dokumente die ermittelt wurden. Technisch gesehen wird die gleiche
|
||||
diese werden direkt auf die Hauptobjekte gefiltert und die Verknüpfung im OpenJPA"=Framework durchgeführt.
|
||||
Somit muss in diesem Beispiel nicht für jedes Dokument eine einzelne Abfrage für die Koautoren durchgeführt werden,
|
||||
es wird lediglich eine Abfrage für alle Dokumente welche ermittelt wurden abgesetzt. Technisch gesehen wird die gleiche
|
||||
WHERE"=Abfrage nochmal durchgeführt und um die JOINS ergänzt, um die Daten der Unterobjekte zu ermitteln.
|
||||
Mit dem Hint \texttt{openjpa.""FetchPlan.""SubclassFetchMode} ist die Konfiguration für Unterklassen definiert. Die
|
||||
Möglichkeiten entsprechen der vom \texttt{openjpa.""FetchPlan.""EagerFetchMode}.
|
||||
|
@ -428,8 +428,8 @@ if (myResultList != null && !myResultList.isEmpty()) {
|
|||
\end{lstlisting}
|
||||
|
||||
Wie in der Messung in \autoref{tbl:measure-criteria-api} zu sehen, unterscheiden sich die Abfragezeiten nur marginal
|
||||
von denen mit \ac{JPQL}. Wenn man sich den Code im Debugger betrachtet, \texthl{ist zu erkennen,} dass die zusammengesetzten
|
||||
Abfragen in den Java-Objekten fast identisch sind. Und in der Datenbank sind die Anfragen identisch zu denen über JPQL.
|
||||
von denen mit \ac{JPQL}. Wenn man sich den Code im Debugger betrachtet, lässt sich erkennen, dass die zusammengesetzten
|
||||
Abfragen in den Java-Objekten fast identisch sind. In der Datenbank sind die Anfragen identisch zu denen über JPQL.
|
||||
|
||||
\begin{table}[h!]
|
||||
\centering
|
||||
|
@ -453,10 +453,10 @@ Abfragen in den Java-Objekten fast identisch sind. Und in der Datenbank sind die
|
|||
\end{table}
|
||||
|
||||
Daher bringt die Criteria API keinen performance Vorteil gegenüber der JPQL"=Implementierung. Somit können beide
|
||||
Implementierung ohne bedenken gegeneinander ausgetauscht werden, und die verwendet werden, die für den Anwendungsfall
|
||||
Implementierungen ohne Bedenken gegeneinander ausgetauscht werden, und die verwendet werden, die für den Anwendungsfall
|
||||
einfacher umzusetzen ist.
|
||||
|
||||
Bei den Hints ist es das gleiche wie bei \ac{JPQL}. Auch hier haben die meisten Hints keinen merkbaren Einfluss. Die
|
||||
Bei den Hints ist es das Gleiche wie bei \ac{JPQL}. Auch hier haben die meisten Hints keinen merkbaren Einfluss. Die
|
||||
Einstellung \texttt{openjpa.""FetchPlan.""EagerFetchMode} liefert auch hier Optimierungen, wenn der Wert auf
|
||||
\textit{parallel} gestellt wird. Hier wird ebenfalls die Anzahl der Anfragen reduziert und damit auch die
|
||||
Geschwindigkeit optimiert.
|
||||
|
@ -612,14 +612,14 @@ vorhanden Elemente, welche die Liste der Dokumente anzeigt, kopiert und auf die
|
|||
\label{tbl:measure-materialized-view}
|
||||
\end{table}
|
||||
|
||||
Wie in \autoref{tbl:measure-materialized-view} zu sehen, bringt die Verwendung der \textit{Materialized View} eine
|
||||
Verbesserung in verschiedenen Punkten. Zum einen ist eine Verbesserung der Aufrufzeiten zu erkennen, zusätzlich fällt
|
||||
Wie in \autoref{tbl:measure-materialized-view} zu sehen ist, bringt die Verwendung der \textit{Materialized View} eine
|
||||
Verbesserung in verschiedenen Punkten. Zum einen ist eine Verbesserung der Aufrufzeiten zu erkennen, zum anderen fällt
|
||||
der Speicheranstieg weniger stark aus. Die Verbesserung der Aufrufzeiten lässt sich zusätzlich erklären, dass hier nun
|
||||
nur noch vier statt der sechs an die Datenbank gestellt werden, da die Einzelabfragen für die Adressen der
|
||||
Personen und der Koautoren komplett entfallen.
|
||||
|
||||
Nach dem der Quellcode nochmal untersucht wurde, konnte man festellen, dass bei jeder Anfrage die gleiche Bedingung
|
||||
benötigt wurden. Da die Sicht nun explizit für dies Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die
|
||||
Nach einer weiteren Untersuchung des Quellcodes konnte man festellen, dass bei jeder Anfrage die gleiche Bedingung
|
||||
benötigt wurden. Da die Sicht nun explizit für diese Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die
|
||||
Sicht mit integriert. Dies bedeutet eine Erweiterung der Sicht aus \autoref{lst:sql-materialized-view} um
|
||||
\autoref{lst:sql-materialized-view-ext} und das Entfernen der Parameter aus dem SQL"=Anfragen im Java"=Code.
|
||||
|
||||
|
@ -654,22 +654,22 @@ zeigen nur minimale Unterschiede in den Zeiten, diese sind auf Messtoleranzen zu
|
|||
|
||||
Da bei der \textit{Materialized View} das Laden der Daten und das Wandeln in die Java"=Objekte getrennt programmiert
|
||||
wurde, können hier eigene Zeitmessungen für die zwei Schritte eingebaut werden. Hierfür wird die Zeit vor dem
|
||||
\texttt{map}"=Aufruf und der \texttt{map}"=Aufruf gemessen. Für den erste Messung, wurde vor der Datenbankabfrage ein
|
||||
\texttt{SearchDocument} Objekt erzeugt und dieses in jedem \texttt{map}"=Aufruf zurückgegeben. Mit dieser Aufbau wurde
|
||||
\texthl{die Zeit ermittelt, um die Daten aus der Datenbank zu laden und dieses Ergebnis einmalig zu durchlaufen} ohne ein \todo{verena}
|
||||
\texttt{map}"=Aufruf und der \texttt{map}"=Aufruf gemessen. Für die erste Messung, wurde vor der Datenbankabfrage ein
|
||||
\texttt{SearchDocument} Objekt erzeugt und dieses in jedem \texttt{map}"=Aufruf zurückgegeben. Mit diesem Aufbau wurde
|
||||
die Zeit ermittelt, um die Daten aus der Datenbank zu laden und dieses Ergebnis einmalig zu durchlaufen ohne ein
|
||||
Objekt zu erstellen. Hierbei lagen die Zeiten bei circa 1 ms für das reine Laden der Daten und 3 ms
|
||||
für den Aufruf der \texttt{map}"=Funktion. Sobald innerhalb der \texttt{map}"=Funktion pro Eintrag ein Objekt
|
||||
erzeugt wird, ohne die Konvertierung der ermittelten Daten in das Objekt, steigt die Laufzeit schon auf 54 ms.
|
||||
erzeugt wird, ohne die Konvertierung der ermittelten Daten in das Objekt, steigt die Laufzeit bereits auf 54 ms.
|
||||
Wenn man nun noch die Konvertierung der Daten mit einbaut, erhöht sich die Laufzeit nochmals, auf nun 82 ms.
|
||||
Alleine für das Erzeugen der Objekte und der Json"=Parse Aufrufe wird die meiste Zeit aufgewendet.
|
||||
|
||||
Bei der Verwendung des Hints \texttt{openjpa.""FetchPlan.""FetchBatchSize} kann die Abfrage enorm verschlechtern. Wenn
|
||||
Bei der Verwendung des Hints \texttt{openjpa.""FetchPlan.""FetchBatchSize} kann sich die Abfrage enorm verschlechtern. Wenn
|
||||
dieser Wert zu klein oder groß definiert ist, wird die Laufzeit verschlechtert. Bei einem zu großen Wert wird die
|
||||
Laufzeit der Datenbankanfrage auf circa 20 ms verlängert. Wenn der Wert zu gering gewählt ist, dann wird zwar die
|
||||
Laufzeit der Datenbankanfrage minimal verkürzt, aber die \texttt{map}"=Funktion wird dadurch verlängert.
|
||||
|
||||
Das Aktivieren der Cache"=Optionen wie in \autoref{sec:performance-investigation-application:caching-openjpa} oder in
|
||||
\autoref{sec:performance-investigation-application:cached-query} dargestellt, haben keine Auswirkung auf die Performance.
|
||||
\autoref{sec:performance-investigation-application:cached-query} \todo{Umbruch} dargestellt, haben keine Auswirkung auf die Performance.
|
||||
Dies ist dadurch erklärbar, das keine Objekte durch das OpenJPA"=Framework erstellt werden, sondern erst in der
|
||||
\texttt{map}"=Funktion des eigenen Codes und daher wird der Cache nicht genutzt.
|
||||
|
||||
|
@ -697,7 +697,7 @@ die \textit{Json}"=Daten aufgerufen wird, wie beim laden der Webseite.
|
|||
\end{lstlisting}
|
||||
|
||||
Die Interpreter"=Funktion, welche in JavaScript geschrieben ist, wird benötigt um die übertragenen
|
||||
\textit{Json}"=Daten in eine darstelle Form zu bringen. Die Funktion aus dem \autoref{lst:jsf-datatable-json-convert}
|
||||
\textit{Json}"=Daten in eine darstellbare Form zu bringen. Die Funktion aus dem \autoref{lst:jsf-datatable-json-convert}
|
||||
ermittelt erst alle versteckten Elemente, deserialisiert den Inhalt und erstellt neue \textit{HTML}"=Elemente mit dem
|
||||
darzustellenden Inhalt. Zusätzlich wird noch eine Zeitmessung eingebaut, um die Laufzeit am Client für das Rendern
|
||||
in der Konsole anzuzeigen. Die Funktion wird nun direkt nach dem die Webseite fertig geladen wurde aufgerufen.
|
||||
|
@ -746,7 +746,7 @@ $(document).ready(function() {
|
|||
Da nun am Client der Code ausgeführt wird, nachdem die Daten übertragen wurden, kann nicht mehr alles über das Script
|
||||
durchgeführt werden. Daher werden nun die Laufzeiten am Server und am Client zusammenaddiert. Im Schnitt benötigt der
|
||||
Aufruf auf der Serverseite nun 70 ms und am Client sind es circa 13 ms. Die summierte Laufzeit von Client und Server
|
||||
ist geringer als die reine Serverlösung und erzeugt gleichzeit weniger Last am Server. \mytodos{verena}
|
||||
ist geringer als die reine Serverlösung und erzeugt gleichzeit weniger Last am Server.
|
||||
|
||||
\section{Optimierung der Abfrage}
|
||||
\label{sec:performance-investigation-application:optimizing-query}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
Nun werden die durchgeführten Anpassungen anhand ihre Effektivität betrachtet und unter welchen äußeren Einflüssen
|
||||
diese eine Optimierung darstellen. Weiterhin werden die Nachteile der Anpassungen überprüft und und bei der Betrachtung
|
||||
der Effektivität mit beachtet. \mytodos{verena}
|
||||
der Effektivität mit beachtet.
|
||||
|
||||
Es wurden die Konfigurationen der Caches von OpenJPA, JPA und EJB aktiviert und deren Auswirkung betrachtet. Bei den
|
||||
Caches, bei denen eine Größe angebbar ist, wurde zusätzlich mit der Anzahl variiert, um zu ermitteln in welchem Umfang
|
||||
|
@ -25,8 +25,8 @@ wurde, ein rein technischer Ansatz.
|
|||
\section{Umgestalten der Datenbanktabellen}
|
||||
\label{sec:evaluation:new-table}
|
||||
|
||||
Hierfür wurde die aktuelle Datenstruktur untersucht um zu prüfen, ob eine Umgestaltung der Tabelle einen Verbesserung
|
||||
bringen würden. Die typische Optimierung ist die Normalisierung der Tabellenstruktur. Die Tabellenstruktur ist aktuell
|
||||
Hierfür wurde die aktuelle Datenstruktur untersucht um zu überprüfen, ob eine Umgestaltung der Tabelle einen Verbesserung
|
||||
bringen würde. Die typische Optimierung ist die Normalisierung der Tabellenstruktur. Die Tabellenstruktur ist aktuell
|
||||
schon normalisiert, daher kann hier nichts weiter optimiert werden.
|
||||
|
||||
Eine weitere Optimierungsstrategie besteht in der Denormalisierung, um sich die Verknüpfungen der Tabellen zu sparen.
|
||||
|
@ -75,7 +75,7 @@ Optimierungsmöglichkeiten.
|
|||
\section{Caching im OpenJPA}
|
||||
\label{sec:evaluation:caching-jpa}
|
||||
|
||||
Bei der Verwendung des OpenJPA"=Caches gibt es einige Verbesserungen in der Geschwindigkeit zu sehen. Die Höhe der
|
||||
Bei der Verwendung des OpenJPA"=Caches gibt es einige Verbesserungen bei der Geschwindigkeit zu sehen. Die Höhe der
|
||||
Optimierungen hängt stark von der gewählten Cache"=Größe und der aufgerufenen Webseiten ab. Solange die Anfragen sich
|
||||
auf die gleichen Objekte beziehen und diese alle im Cache hinterlegt werden können, fällt die Optimierung entsprechend
|
||||
hoch aus. Sobald bei den Anfragen aber häufig die zu ermittelnden Objekte sich unterscheiden und alte Objekte wieder
|
||||
|
@ -83,8 +83,8 @@ aus dem Cache entfernt werden, fällt die Performance"=Verbesserung immer gering
|
|||
|
||||
Das Entfernen der Objekte kann zwar umgangen werden, indem die häufig abgefragten Objekte gepinnt werden, was aber
|
||||
den Speicherbedarf noch weiter erhöht, da diese Objekte nicht in die Zählung der Cache"=Objekte beachtet werden.
|
||||
Was uns direkt zum größten Nachteil diese Caches kommen lässt, die notwendig Speichermenge die ständig zur Verfügung
|
||||
gestellt werden muss. Damit ist immer ein gewisser Grundbedarf notwendig, da sich der Speicher bis zum eingestellten
|
||||
Als größten Nachteil des Caches ist zu nennen, dass die notwendige Speichermenge ständig zur Verfügung gestellt
|
||||
werden muss. Damit ist immer ein gewisser Grundbedarf notwendig, da sich der Speicher bis zum eingestellten
|
||||
Grenzwert aufbaut und dann nicht mehr entleert wird. Gerade bei kleiner dimensionierten Servern stellt dies ein
|
||||
größeres Problem dar, da nun weniger Speicher für die anderen laufenden Programme, wie dem Datenbankmanagementsystem,
|
||||
zur Verfügung steht.
|
||||
|
@ -106,7 +106,7 @@ explizit im Cache aufgenommen und angepinnt werden.
|
|||
Die Optimierung über die gespeicherten Anfragen brachte keine Verbesserung hervor. Dies ist dadurch erklärbar, dass
|
||||
für die diese Art nur Anfragen verwendet werden, die keinerlei Bedingungen besitzen. In diesem Fall sind in der Tabelle
|
||||
noch nicht freigegebene und ungültige Datensätze gespeichert, daher müssen diese vor dem Übertragen herausgefiltert
|
||||
werden. Aus diesem Grund werden die Anfragen in diesem Cache nicht gespeichert werden.
|
||||
werden. Aus diesem Grund werden die Anfragen in diesem Cache nicht gespeichert.
|
||||
|
||||
Dadurch ist dieser Cache für eine Performance"=Verbesserung in dem Fall der Dokumentenliste nicht anwendbar.
|
||||
|
||||
|
@ -153,14 +153,14 @@ keine nennenswerten Einfluss auf die Laufzeit der Abfragen und Übertragung in d
|
|||
von OptimizeResultCount, der FetchSize sowie der FetchBatchSize hilft dem Framework die Bearbeitung der Anfrage
|
||||
effizient abzuarbeiten, konnte aber in den gemessenen Laufzeiten nicht verifiziert werden.
|
||||
|
||||
Anders verhält sich dies mit den Einstellungen für EagerFetchMode, welche definiert wie die Daten für abhängige Klasse
|
||||
Anders verhält sich dies mit der Einstellung für \texttt{EagerFetchMode}, welche definiert, wie die Daten für abhängige Klassen
|
||||
ermittelt werden. Bei der Umstellung auf \textit{parallel} konnte für die Ermittlung der Dokumente einiges an Performance gewonnen
|
||||
werden. Das liegt daran, dass nun für die abhängigen Objekte, wie den Koautoren, nicht pro Dokument eine Anfrage an die
|
||||
Datenbank gestellt wird, sondern es werden alle Koautoren für die ermittelten Dokumente auf einmal ermittelt. Die
|
||||
Zuordnung der Koautoren zu dem Dokument wird dann nun im Framework und nicht mehr durch die Datenbank durchgeführt.
|
||||
Diese Abarbeitung reduziert viele einzelne Abfragen und somit auch den entsprechend Overhead im Framework.
|
||||
|
||||
Auf Grund dessen ist die Entscheidung der Technik für die Performance irrelevant und es kann das genutzt werden, was für
|
||||
Folglich ist die Entscheidung der Technik für die Performance irrelevant und es kann das genutzt werden, was für
|
||||
jeweiligen Einsatzzweck besser beziehungsweise einfacher zu programmieren ist. Das Setzen der richtigen Hints wiederrum
|
||||
ist in beiden Fällen äußerst wichtig. Explizit bei der EagerFetchMode muss vorher darüber nachgedacht werden, wie viele
|
||||
abhängige Objekttypen es zu dieser Klasse gibt, welche dazu geladen werden sollen und von welcher Anzahl an Objekte
|
||||
|
@ -172,11 +172,11 @@ Gleiches gilt dem Hint SubclassFetchMode, dieser steuert dimensionierte Abfragen
|
|||
|
||||
Die Idee der \textit{Materialized View} ist simple aber sehr effizient, gerade für einen Datenbestand welcher häufig gelesen
|
||||
und selten verändert wird. Hierbei werden komplexe Abfragen einmalig ausgeführt und das Ergebnis intern
|
||||
zwischengespeichert. Für alle weiteren Aufrufe, werden die Daten nun aus der Zwischenspeicher gelesen und dem Aufrufer
|
||||
zwischengespeichert. Für alle weiteren Aufrufe, werden die Daten nun aus dem Zwischenspeicher gelesen und dem Aufrufer
|
||||
zurückgegeben. Der größte Nachteil der \textit{Materialized View} ist, dass bei einer Änderung an den Quelldaten die
|
||||
Sicht aktualisiert werden muss. Dieser Nachteil kommt in einer Briefedition nicht zum tragen, da in dieser nach dem die
|
||||
Briefe einmalig eingepflegt wurden, nur noch selten Änderungen erfahren. Die Recherche über den Datenbestand die größte Zeit
|
||||
gewidmet wird.
|
||||
Briefe einmalig eingepflegt wurden, nur noch selten Änderungen erfahren. Die Recherche zu dem Datenbestand wird die
|
||||
meiste Zeit gewidmet.
|
||||
|
||||
Ein weiterer Nachteil der \textit{Materialized View} ist die doppelte Speicherung der Daten, da die Daten für die Sicht
|
||||
wie bei einer Tabelle auf der Festplatte gespeichert sind. Dieser Nachteil ist in der Dokumentliste vernachlässigbar,
|
||||
|
@ -191,14 +191,14 @@ konnten schon viele zusätzliche Abfragen eingespart werden, da diese nicht mehr
|
|||
für jede Datenzeile einzeln durchgeführt wird.
|
||||
|
||||
Zusätzlich konnte dies nochmal beschleunigt werden, in dem das Parsen der \textit{Json}"=Daten vom Server auf den Client
|
||||
verlagert wurde. Hiermit konnte zum einen Last vom Server genommen werden und die gesamte Ausführungszeit nochmals
|
||||
optimieren. Die Wandlung der Daten in \textit{HTML}"=Objekte ist eine Kernkompetenz von JavaScript und damit auch bei
|
||||
verlagert wurde. Hiermit konnte ein Teil der Last vom Server genommen und die gesamte Ausführungszeit nochmals
|
||||
optimiert werden. Die Wandlung der Daten in \textit{HTML}"=Objekte ist eine Kernkompetenz von JavaScript und damit auch bei
|
||||
schwächeren Clients in kurzer Zeit durchführbar.
|
||||
|
||||
Als weiteren Punkt ist anzumerken, das der Speicherbedarf des Webserver relativ konstant bleibt ohne das ein Cache
|
||||
verwendet wird. Der größte Unterschied zur Standardimplementierung ist die Verwendung von eigenen Code um die Objekte
|
||||
Als weiteren Punkt ist anzumerken, dass der Speicherbedarf des Webserver relativ konstant bleibt ohne das ein Cache
|
||||
verwendet wird. Der größte Unterschied zur Standardimplementierung ist die Verwendung von eigenen Codes um die Objekte
|
||||
zu erstellen und zu befüllen und es nicht durch das OpenJPA"=Framework durchführen zu lassen.
|
||||
Dies legt den Schluss nahe, dass es Probleme in der Speicherverwaltung der Objekte im OpenJPA"=Framework existieren.
|
||||
Dies legt den Schluss nahe, dass Probleme in der Speicherverwaltung der Objekte im OpenJPA"=Framework existieren.
|
||||
|
||||
Zusammenfassend ist zu sagen, dass die \textit{Materialized View} eine gute Wahl ist, um die Listendarstellungen
|
||||
zu optimieren. Mit dieser Technik können zum einen die Abfragezeiten optimiert werden, wodurch gleichzeit die
|
||||
|
@ -209,7 +209,7 @@ ist oder direkt auf denormalisierte Daten umgestellt werden sollte, weil der zus
|
|||
die Quelle ist.
|
||||
Im Gegensatz zu einer reinen Cache"=Lösung die die gleiche Optimierung besitzt, ist diese vorzuziehen, da in den
|
||||
meisten Fällen der Festplattenspeicher kostengünstiger als der Arbeitsspeicher ist. Zusätzlich ist der Cache begrenzt
|
||||
und wirft alte Objekte aus dem Cache. Wenn dieser voll ist und wird ein Zugriff auf diese entfernten Objekte
|
||||
und wirft alte Objekte heraus. Wenn dieser voll ist wird ein Zugriff auf diese entfernten Objekte
|
||||
langsamer. Somit ist die Optimierung über die \textit{Materialized View} auf lange Zeit gesehen kostengünstiger und
|
||||
stabiler.
|
||||
|
||||
|
@ -217,20 +217,21 @@ stabiler.
|
|||
\label{sec:evaluation:optimize-query}
|
||||
|
||||
Die Abfragen die durch die OpenJPA an die Datenbank abgesetzt werden, sind meist durch ihre Einfachheit gut optimiert.
|
||||
Nur durch Sortierung oder Bedingungen können die Abfragen langsam werden. Diese können durch entsprechende Indexe
|
||||
Nur durch Sortierung oder Bedingungen können die Abfragen langsamer werden. Diese können durch entsprechende Indexe
|
||||
gelöst werden. Bei größeren Abfragen mit mehreren Joins kann durch geschicktes umstellen die Performance verbessert
|
||||
werden. Die Hauptabfrage der Dokumentenliste besteht aus mehreren Joins und diese wurde explizit untersucht.
|
||||
|
||||
Der Abfrageplan der Hauptabfrage wurde visuell untersucht und zeigt, dass das Hauptproblem die nicht eingeschränkte
|
||||
Datenmenge der Haupttabelle \textit{document} ist. Dadurch werden zum einen die anderen Tabellen komplett dazu geladen
|
||||
und es werden trotz direkter Primary Key Bedingungen keine Zugriffe über die Index durchgeführt. Für den PostgreSQL
|
||||
Datenmenge der Haupttabelle \textit{document} ist. Dadurch werden die anderen Tabellen komplett geladen
|
||||
anstatt die Zugriffe über die vorhandenen Indexe durchzuführen, obwohl die Bedingungen über die Primary Key definiert
|
||||
sind. Für den PostgreSQL
|
||||
ist es laut Berechnung kostengünstiger mit einem \textit{Seq Scan}, was einem kompletten Durchlaufen der Tabelle
|
||||
entspricht, zu arbeiten.
|
||||
|
||||
Um dies zu optimieren, wurde über eine \textit{Common Table Expression} zuerst die eingeschränkten Datenzeilen
|
||||
ermittelt, dieser mit der Haupttabelle verknüpft und nun die anderen Tabellen dazugenommen. Hierdurch konnten die
|
||||
ermittelt, dieser mit der Haupttabelle verknüpft und nun die anderen Tabellen dazugenommen. Hierdurch konnte die
|
||||
Zeilenanzahl während der Verarbeitung enorm verringert werden, wodurch einige der Verknüpfungen auf Indexzugriffe
|
||||
umgestellt wurden. Durch die Umstellung konnte die Abfragezeit um mehr als das dreifache reduziert wurde.
|
||||
umgestellt wurden. Durch die Umstellung konnte die Abfragezeit um mehr als das dreifache reduziert werden.
|
||||
|
||||
Mit dieser Art der Umstellung können Abfragen optimiert werden, die fürs Paging verwendet werden und die Abfrage aus
|
||||
mehrere Tabellen besteht. Das Wichtigste hierbei ist, dass die Bedingungen und die Sortierkriterien auf der
|
||||
|
|
|
@ -12,19 +12,17 @@
|
|||
Die Untersuchungen am Beispiel des Wedekind"=Projektes zeigen, dass mehrere Optimierungsmöglichkeiten in den
|
||||
Briefeditionen existieren. Für die Untersuchung wurde sich auf die Dokumentenliste beschränkt und anhand dieser
|
||||
die Optimierung implementiert, untersucht und jeweils mit der Ausgangsmessung vergleichen. Für die Messung wurden
|
||||
Skripte erstellt, die auf dem gleichen Computer wie der Webserver und der Datenbankserver laufen, damit diese auch
|
||||
Skripte erstellt, welche auf dem gleichen Computer wie der Webserver und der Datenbankserver laufen, damit diese auch
|
||||
vergleichbar bleiben und externe Einflussfaktoren minimiert werden.
|
||||
|
||||
\mytodos{den Absatz hier drin lassen oder raus?}
|
||||
%Messung zeigt wo die Probleme liegen! hier noch ausformulieren
|
||||
Durch die Ausgangsmessungen war erkennbar, dass der größte Teil der Verarbeitungszeit im Bereitstellen der Entitäten
|
||||
benötigt wird. Die Messung der Abfragen auf der Datenbank wiederum konnte die hohe Verarbeitungszeit nicht bestätigen,
|
||||
daher lag hier schon die Vermutung nahe, dass der Großteil der Zeit im ORM"=Mapper verloren geht.
|
||||
liegt. Die Messung der Abfragen auf der Datenbank wiederum konnte die hohe Verarbeitungszeit nicht bestätigen,
|
||||
daher lag hier die Vermutung nahe, dass der Großteil der Zeit im ORM"=Mapper verloren geht.
|
||||
|
||||
Die Methode der Nutzerumfrage wurde nicht weiterverfolgt, da diese auf Grund zu wenigen Bedienern nicht zielführend war.
|
||||
Bei der Untersuchung der Datenbank, wurde festgestellt, dass die Struktur aktuell für die Anwendung optimal ist und
|
||||
Bei der Untersuchung der Datenbank wurde festgestellt, dass die Struktur aktuell für die Anwendung optimal ist und
|
||||
daher eine Restrukturierung keine Vorteile entstehen lässt. Die statische Webseite und die komplett Client basierte
|
||||
Webseite wurde auf Grund von technischen Einschränkungen nicht weiterverfolgt.
|
||||
Webseite wurden auf Grund von technischen Einschränkungen nicht weiterverfolgt.
|
||||
|
||||
Bei den Caches sind der Query"=Cache und der EJB"=Cache nicht für die Optimierung verwendbar. Der Query"=Cache wird
|
||||
von OpenJPA nur verwendet, wenn die Abfragen keine Parameter besitzt, welche in der Dokumentliste verwendet werden
|
||||
|
@ -34,7 +32,7 @@ Performance festgestellt werden konnte.
|
|||
Anders sieht es bei dem OpenJPA"=Cache aus, dieser hat direkten Einfluss auf die Performance der Ermittlung der Daten
|
||||
und Bereitstellung der dazugehörigen Java"=Objekte. Anhand der vorgegeben Cache"=Größe kann das Potential der
|
||||
Optimierung eingestellt werden. Dies bedeutet, soweit der Cache groß genug ist um alle notwendigen Objekte zu
|
||||
speichern, sind die Verbesserung gut sichtbar. Ab dem Zeitpunkt ab dem Objekte aus dem Cache entfernt werden müssen,
|
||||
speichern, sind die Verbesserungen gut sichtbar. Ab dem Zeitpunkt ab dem Objekte aus dem Cache entfernt werden müssen,
|
||||
wird die Optimierung immer geringer.
|
||||
|
||||
Ein sehr ähnliches Verhalten konnte mit dem Ehcache festgestellt werden, nur dass bei diesem die Limitierungen höher
|
||||
|
@ -44,41 +42,41 @@ In beiden Fällen der Optimierung über die Nutzung eines Caches, konnte durch d
|
|||
Abfragen an der Datenbank nachgewiesen werden, dass nicht das Ermitteln der Daten die größte Zeit einnimmt, sondern
|
||||
das Erstellen und Befüllen der Objekte in Java.
|
||||
|
||||
Bei dem Vergleich der unterschiedlichen Abfragemethoden Criteria API und JPQL konnte keine Unterschied in der
|
||||
Bei dem Vergleich der unterschiedlichen Abfragemethoden Criteria API und JPQL konnte kein Unterschied in der
|
||||
Performance und Abarbeitung festgestellt werden. Bei beiden Methoden konnte nachgewiesen werden, dass die syntaktisch
|
||||
gleichen Abfragen an die Datenbank gestellt wurden. Bei den Abfragen zur Dokumentenliste konnten in beiden Fällen
|
||||
durch die Umstellung der Ermittlung der unterlagerten Daten durch Hints eine Optimierung erreicht werden. Die Umstellung
|
||||
bezweckt das die unterlagerten Daten nicht einzeln für jede Zeile ermittelt wurde, sondern alle Daten auf einmal
|
||||
bezweckt das die unterlagerten Daten nicht einzeln für jede Zeile ermittelt wurden, sondern alle Daten auf einmal
|
||||
geladen werden und die Zuordnung der Datensätze im OpenJPA"=Framework durchgeführt wird.
|
||||
|
||||
Mit der Übernahme der \textit{Materialized View} aus dem Wedekind"=Projekt konnte erstmalig ein gute Optimierung
|
||||
beobachtet werden. Dies ist auf die einfachere Abfrage, die Reduzierung der Abfrage an den Datenbankserver und das
|
||||
die Objekte in eigenen Code erstellt werden und nicht durch das OpenJPA"=Framework. Hierbei konnte noch nachgewiesen
|
||||
die Objekte im eigenen Code erstellt werden und nicht durch das OpenJPA"=Framework. Hierbei konnte noch nachgewiesen
|
||||
werden, dass das Parsen der Json"=Daten, die die unterlagerten Objekte enthalten, den größten Teil der Zeit benötigen.
|
||||
Auf Grund dessen wurde das Parsen der Json"=Daten auf den Client verschoben, was zu einem noch besseren Ergebnis führte.
|
||||
|
||||
Für die Optimierung der Abfragen wurde die Hauptabfrage betrachtet. Bei dieser konnte anhand der visuellen Darstellung
|
||||
das Problem gut identifiziert werden. Durch die Verwendung einer \textit{Common Table Expression} wurde die Anzahl
|
||||
der Datensatze direkt am Anfang auf die angefragte Menge reduziert, wodurch die Anzahl der zu betrachteten Datensätze
|
||||
für die weiteren Verlinkungen enorm reduziert wurden. Somit konnte der Datenbankserver bei diesen Verlinkung auf Indexe
|
||||
der Datensätze direkt am Anfang auf die angefragte Menge reduziert, wodurch die Anzahl der zu betrachteten Datensätze
|
||||
für die weiteren Verlinkungen enorm reduziert wurde. Somit konnte der Datenbankserver bei diesen Verlinkung auf Indexe
|
||||
zugreifen und damit die Abfragen zusätzlich beschleunigen.
|
||||
|
||||
Die Untersuchungen zeigen, dass mehrere Möglichkeiten zur Optimierung existierten, um die Zugriffe auf die
|
||||
Briefeditionen zu beschleunigen und das das größte Optimierungspotential in den ORM"=Mapper vorhanden ist. Welche der
|
||||
Optimierungen verwendet werden, liegt zum einen an der Komplexität der Abfrage und der bereitgestellten Ressourcen
|
||||
Briefeditionen zu beschleunigen und das das größte Optimierungspotential in dem ORM"=Mapper liegt. Welche der
|
||||
Optimierungen verwendet werden, liegt an der Komplexität der Abfrage und der bereitgestellten Ressourcen
|
||||
des Servers.
|
||||
|
||||
\section{Ausblick}
|
||||
\label{sec:summary_and_outlook:outlook}
|
||||
|
||||
Die Untersuchungen zeigen, dass die Schichten über OpenJPA weitestgehend optimal umgesetzt sind, beziehungsweise wenig
|
||||
Möglichkeiten für eine Optimierungen zu lassen. Einzig das Parsen von Json ist in einem Webbrowser schneller als im
|
||||
Möglichkeiten für eine Optimierungen zulassen. Einzig das Parsen von Json ist in einem Webbrowser schneller als im
|
||||
Server durchführbar. Auf diese Weise könnten zusätzlich die Ressourcen am Server reduziert werden beziehungsweise mit
|
||||
gleichen Ressourcen mehr Anfragen als bisher beantwortet werden.
|
||||
|
||||
Die größten Optimierungspotentiale können durch Umstellung der Abfragen und der Optimierung des ORM"=Mappers umgesetzt
|
||||
werden. Bei den Umstellungen der Abfragen ist größte Stärke, wenn die Anzahl der Abfragen drastisch reduziert werden
|
||||
können.
|
||||
könnte.
|
||||
|
||||
Dadurch zeigt sich, dass die Untersuchung auf Ebene der ORM"=Mapper noch nicht abgeschlossen ist. Weitere Untersuchungen
|
||||
nach anderen ORM"=Mapper könnten wie in \ref{sec:evaluation:materialized-view} angedeutet das Speicherproblem lösen,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue