diff --git a/.vscode/settings.json b/.vscode/settings.json index de31114..e187b2d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "autovacuum", "denormalisierte", "Denormalisierung", + "deserialisiert", "editionswissenschaftlich", "EFFW", "Ehcache", @@ -57,6 +58,8 @@ "adressee", "ajax", "american", + "appuser", + "appuserrole", "asadmin", "authorperson", "birthstartday", @@ -80,6 +83,7 @@ "endday", "endmonth", "endyear", + "extendedbiography", "ferniunithesis", "firstname", "fmtutil", @@ -105,6 +109,7 @@ "searchdocument", "searchfulltext", "searchreference", + "seqscan", "servlet", "servlets", "sitecity", diff --git a/chapters/expose/chapter01.tex b/chapters/expose/chapter01.tex index 8180e7f..a3071b2 100644 --- a/chapters/expose/chapter01.tex +++ b/chapters/expose/chapter01.tex @@ -73,7 +73,7 @@ zu verringern. Um Anfragen die den Zugriff auf die Festplatte benötigen effizie every fit/.style={inner sep=1em,draw} ] %https://docs.oracle.com/javaee/6/tutorial/doc/bnacj.html - \node (browser) [block] {WebBrowser}; + \node (browser) [block] {Webbrowser}; \node (fitClient) [fit=(browser)] {}; \node [left] at (fitClient.west) {Client}; @@ -113,13 +113,13 @@ von Datenbankverbindungen zu definieren \citep[68]{MüllerWehr2012}. Dadurch kan gehalten werden als die Anzahl der Benutzer die an der Anwendung arbeiten. Zusätzlich werden die Transaktionen über \textit{Stateful Session-Bean (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 Performanz-Problemen +Entities in den \textit{Persistenzkontext} geladen werden. Da dies häufig zu Speicher"= und damit Performance"=Problemen \citep[79]{MüllerWehr2012} führen kann, muss hier darauf geachtet werden, nicht mehr benötigte Entities aus dem \textit{Persistenzkontext} zu lösen. \subsection{Glassfish - Java Persinstance API} -Die \textit{Java Persistence API (JPA)} wird als First-Level-Cache in Java-EE-An\-wen\-dung verwendet, hier nehmen die +Die \textit{\ac{JPA}Java Persistence API (JPA)} wird als First-Level-Cache in Java-EE-An\-wen\-dung verwendet, hier nehmen die Objekte einen von vier Zuständen ein \citep[57]{MüllerWehr2012}. Im Zustand \textit{Transient} sind die Objekt erzeugt, aber noch nicht in den Cache überführt worden. Wenn diese in den Cache überführt worden sind, nehmen sie den Zustand \textit{Verwaltet} ein. Ist das Objekt aus dem Cache und der Datenbank entfernt worden, nimmt es den Zustand diff --git a/chapters/thesis/appendix04.tex b/chapters/thesis/appendix04.tex index 4c33a91..fb1c5fd 100644 --- a/chapters/thesis/appendix04.tex +++ b/chapters/thesis/appendix04.tex @@ -12,7 +12,7 @@ Um die Messungen etwas zu vereinfachen wurde ein Skript erstellt um die Aufrufe Messungen durchzuführen werden die Befehl, wie in \autoref{lst:calling_script_exec} dargestellt aufgerufen. Durch die nummerierten Präfixe können im Nachgang über die \textit{pgBadger}"=Berichte die \ac{SQL}"=Abfragen verglichen 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, +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. diff --git a/chapters/thesis/appendix06.tex b/chapters/thesis/appendix06.tex index 32a8b0a..c4e1c32 100644 --- a/chapters/thesis/appendix06.tex +++ b/chapters/thesis/appendix06.tex @@ -8,10 +8,10 @@ \chapter{JSF Performance Measure} \label{ap:jsf_performance_measure} -Für die Protokollierung der Abläufe im \ac{JSF} werden zwei Klassen benötigt. Die Factory \ref{lst:logger_factory}, +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. -Zusätzlich muss in der Konfiguration \textbf{faces-config.xml} noch angepasst werden, wie in +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. \includecode[java]{chapters/thesis/appendix06_Logger.java}{lst:logger}{Vdi Logger} diff --git a/chapters/thesis/chapter01.tex b/chapters/thesis/chapter01.tex index f99d788..4e1eb35 100644 --- a/chapters/thesis/chapter01.tex +++ b/chapters/thesis/chapter01.tex @@ -3,10 +3,12 @@ \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 wird +werden, dass die Anwendung immer in kurzer Zeit reagiert oder entsprechende Anzeigen dargestellt werden um eine längere Bearbeitung anzuzeigen. %\section{Motivation} @@ -48,7 +50,7 @@ der Hochschule Darmstadt und der Fernuni Hagen umgesetzt und durch die Deutsche Das entstandene Pilotprojekt ist eine webbasiert Anwendung, die aktuell unter \url{http://briefedition.wedekind.h-da.de} eingesehen werden kann. Hierbei wurden sämtliche bislang bekannte Korrespondenzen in dem System digitalisiert. Die -Briefe selbst werden im etablierten TEI-Format gespeichert und über einen WYSIWYG-Editor von den Editoren und +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 @@ -61,10 +63,8 @@ Die aktuelle Umsetzung beinhaltet die bisher definierten Anforderungen vollstän 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 der Arbeit ist es, die Abfragedauer zu verringern, wodurch die Performance der Oberfläche signifikant -verbessert wird. - -Hierbei ist auch ein Vergleich mit anderen Techniken angedacht. +Das Ziel dieser Arbeit ist es, die Abfragedauer zu verringern, wodurch die Performance der Oberfläche signifikant +verbessert wird. \mytodos{verena} \section{Gliederung} \label{sec:intro:structure} @@ -79,21 +79,22 @@ Hierzu gehören zum einen die Einstellungen der verwendeten Software, und zum an 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"=Untersuchung in \autoref{ch:performance-checking} werden nun die Konzepte angewandt, um +Bei den Performance"=Untersuchungen im \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. +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"=Untersuchung der Anwendung aufzeigt. +Performance"=Untersuchungen der Anwendung aufzeigt. Zuerst wird im \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 dann in Abhängigkeit zur Ausgangsmessung die Optimierung bewertet. +wird mit der Ausgangsmessung verglichen und bewertet. Nach der Optimierung kommt nun die Evaluierung im \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. -Zum Abschluss im Kapitel \ref{ch:summary_and_outlook} wird explizit die Anpassungen dargestellt, die zu einer -merklichen Verbesserung geführt haben und wie diese entsprechend umgesetzt werden müssen. Zusätzliche wird +\todo{verena} +Zum Abschluss im \autoref{ch:summary_and_outlook} \texthl{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. diff --git a/chapters/thesis/chapter02.tex b/chapters/thesis/chapter02.tex index d35636d..eb7a841 100644 --- a/chapters/thesis/chapter02.tex +++ b/chapters/thesis/chapter02.tex @@ -6,16 +6,17 @@ Da die Anwendung als Webseite umgesetzt ist, ist der zugehörige Client für den Benutzer ein Webbrowser. Dies bedeutet, dass jeder Wechsel einer Seite oder eine Suchanfrage als Web"=Request an den Server geschickt wird. Solch ein Web"=Request geht durch mehrere Schichten des Server"=System bis die Antwort an den Client zurückgesendet wird, wie in -\ref{fig:webrequest} dargestellt. +\autoref{fig:webrequest} dargestellt. -Es wird ab hier immer von einem \textit{Glassfish}"=Server geredet. In der Praxis wird ein \textit{Payara}"=Server +\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 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 diese mit regelmäßigen Aktualisierungen versorgt wird. In dem weiteren Text -wird weiterhin der Begriff \textit{Glassfish} verwendet. +und ist für Produktivumgebungen gedacht, da dieser mit regelmäßigen Aktualisierungen versorgt wird. In dem weiteren 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 -empfangen wird. In diesem wird anhand des definierten Routing entschieden, an welchen \textit{Controller} im \ac{JSF} +empfangen wird. In diesem wird anhand des definierten Routing entschieden, an welchen \textit{Controller} im \textit{\ac{JSF}} die Anfrage weitergeleitet und verarbeitet wird. In diesem wird die Darstellung der Webseite geladen und die Anfragen für den darzustellenden Datenbestand abgeschickt. @@ -25,7 +26,7 @@ an das unterlagerte Datenbankmanagementsystem \textit{PostgreSQL} weitergeleitet 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 +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 \textit{Services} die Datenstrukturen auf. @@ -36,7 +37,7 @@ zu verringern. Um Anfragen die den Zugriff auf die Festplatte benötigen effizie every fit/.style={inner sep=1em,draw} ] %https://docs.oracle.com/javaee/6/tutorial/doc/bnacj.html - \node (browser) [block] {WebBrowser}; + \node (browser) [block] {Webbrowser}; \node (fitClient) [fit=(browser)] {}; \node [left] at (fitClient.west) {Client}; @@ -73,11 +74,11 @@ 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 Verbindung geringer +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 \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 Performanz"=Problemen +Entities in den \textit{Persistenzkontext} geladen werden. Da dies häufig zu Speicher"~ und damit Performance"=Problemen \citep[79]{MüllerWehr2012} führen kann, muss hier darauf geachtet werden, nicht mehr benötigte Entities aus dem \textit{Persistenzkontext} zu lösen. @@ -85,40 +86,41 @@ Entities in den \textit{Persistenzkontext} geladen werden. Da dies häufig zu Sp \label{sec:basics:jpa} Die \textit{\ac{JPA}} wird als First"=Level"=Cache in Java"=EE"=Anwendung verwendet, hier nehmen die -Objekte einen von vier Zuständen ein \citep[57]{MüllerWehr2012}. Im Zustand \textit{Transient} sind die Objekt erzeugt, +Objekte einen von vier Zuständen ein \citep[57]{MüllerWehr2012}. Im Zustand \texttt{Transient} sind die Objekte erzeugt, aber noch nicht in den Cache überführt worden. Wenn diese in den Cache überführt worden sind, nehmen sie den Zustand -\textit{Verwaltet} ein. Ist das Objekt aus dem Cache und der Datenbank entfernt worden, nimmt es den Zustand -\textit{Gelöscht} an. \textit{Losgelöst} ist der letzte Zustand, bei dem das Objekt aus dem Cache entfernt worden ist, +\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. Eine Menge von Objekten wird als \textit{Persistenzkontext} bezeichnet. Solange die Objekte dem -\textit{Persistenzkontext} zugeordnet sind, also den Zustand \textit{Verwaltet} besitzen, werden diese auf Änderungen -überwacht, um sie am Abschluss mit der Datenbank zu synchronisieren. In der Literatur wird hierzu der Begriff +\textit{Persistenzkontext} zugeordnet sind, also den Zustand \texttt{Verwaltet} besitzen, werden diese auf Änderungen +überwacht, um diese am Abschluss mit der Datenbank zu synchronisieren. In der Literatur wird hierzu der Begriff \textit{Automatic Dirty Checking} verwendet \citep[61]{MüllerWehr2012}. \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}. -Gegen die Verwendung spricht, dass die Daten im \textit{Second Level Cache} explizit über Änderungen informiert werden -müssen, welche sonst beim nächsten Aufruf veraltete Werte liefern. Ebenfalls benötigt so ein Cache einen höheren Bedarf +\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 an Arbeitsspeicher, in dem die Daten parallel zur Datenbank bereitgestellt werden, daher ist die Benutzung nur -problemlos bei Entities möglich, auf die meist lesend zugegriffen wird. +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} -bezeichnet) und Query-Cache unterschieden. Über die Funktionen \texttt{find()} und \texttt{refresh()} oder einer Query +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 zurückliefern, aber nicht das Entity selbst. Hierbei kann genau gesteuert werden, welche Entity in den Cache abgelegt -wird und welche nicht. Ebenfalls kann auf Klassenbasis der zugehörige Cache definiert werden, um eine bessere +werden und welche nicht. Ebenfalls kann auf Klassenbasis der zugehörige Cache definiert werden, um eine bessere Last-Verteilung beim Zugriff zu ermöglichen \citep[314]{MüllerWehr2012}. -Im \textit{Query-Cache} werden die Abfragen beziehungsweise die Eigenschaften einer Abfrage und die zurückgelieferten Ids der -Entities gespeichert. Bei einen erneuten Aufruf dieser Abfrage werden die referenzierten Objekte aus dem -\textit{Objekt-Cache} zurückgegeben. Bei veränderten referenzierten Entities wird der \textit{Query-Cache} nicht -genutzt und die betroffenen Abfragen werden unverzüglich aus dem \textit{Query-Cache} entfernt +Im \textit{Query"=Cache} werden die Abfragen beziehungsweise die Eigenschaften einer Abfrage und die zurückgelieferten Ids der +Entities gespeichert. Bei einem erneuten Aufruf dieser Abfrage werden die referenzierten Objekte aus dem +\textit{Objekt"=Cache} zurückgegeben. Bei veränderten referenzierten Entities wird der \textit{Query"=Cache} nicht +genutzt und die betroffenen Abfragen werden unverzüglich aus dem \textit{Query"=Cache} entfernt \citep[316]{MüllerWehr2012}. Um zu prüfen, ob die Einstellungen sinnvoll gesetzt sind, kann in OpenJPA eine Cache"=Statistik abgefragt werden. Mit @@ -129,20 +131,20 @@ 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 \textit{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 \textit{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. -Der \textit{work\_mem} definiert die Obergrenze des zur Verfügung gestellt Hauptspeichers pro Datenbankoperation wie -effizientes Sortieren, Verknüpfen oder Filtern. Ebenso wird im Falle eines zu klein gewählten Speichers auf temporäre -Dateien auf der Festplatte ausgewichen, was signifikanten Leistungseinbrüchen zur Folge haben kann. +Der \texttt{work\_mem} definiert die Obergrenze des zur Verfügung gestellt Hauptspeichers pro Datenbankoperation wie +effizientes sortieren, verknüpfen oder filtern. Ebenso wird im Falle eines zu klein gewählten Speichers auf temporäre +Dateien auf der Festplatte ausgewichen, was signifikante Leistungseinbrüche zur Folge haben kann. -Die \textit{maintenance\_work\_mem} wird bei Verwaltungsoperationen wie Änderungen und Erzeugungen von Datenbankobjekten +Die \texttt{maintenance\_work\_mem} wird bei Verwaltungsoperationen wie Änderungen und Erzeugungen von Datenbankobjekten als Obergrenze definiert. Die Wartungsaufgabe \texttt{VACUUM}, welche die fragmentierten Tabellen aufräumt und somit die Performance hebt, beachtet die Obergrenze ebenfalls. @@ -153,7 +155,7 @@ Die Wartung des Datenbanksystems ist eine der wichtigsten Aufgaben und sollte re durchgeführt werden, damit die Performance des Systems durch die Änderungen des Datenbestands nicht einbricht \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 \textit{autovacuum\_work\_mem} gesondert definiert werden \citep{PostgresPro:Chap20.4:2023}. +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} \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. @@ -169,11 +171,11 @@ Für weitere Optimierungen werden anschließend die Anfragen einzeln überprüft 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}. 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 der wichtigsten Kennzeichen hierbei ist, ob die Zeilenschätzung akkurat war. +Größere Abweichungen weißen 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 +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, 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. diff --git a/chapters/thesis/chapter03.tex b/chapters/thesis/chapter03.tex index d2d8352..d236ab2 100644 --- a/chapters/thesis/chapter03.tex +++ b/chapters/thesis/chapter03.tex @@ -11,34 +11,34 @@ auf mögliche Optimierungen untersucht und bewertet. \section{Allgemeine Betrachtung des Systems} \label{sec:concept:viewsystem} -Für die Untersuchung des Systems wird der direkte Zugang zum Server benötigt. Hierbei werden zuerst die im Kapitel -\ref{sec:basics:services} beschriebenen Einstellungen überprüft. +Für die Untersuchung des Systems wird der direkte Zugang zum Server benötigt. Hierbei werden zuerst die im +\autoref{sec:basics:services} beschriebenen Einstellungen überprüft. Zuerst wird am PostgreSQL"=Server die Konfiguration der Speicher mit der Vorgabe für Produktivsysteme abgeglichen. -Hierunter fallen die Einstellungen für die \textit{shared\_buffers}, der bei einem Arbeitsspeicher von mehr als 1 GB +Hierunter fallen die Einstellungen für die \texttt{shared\_buffers}, der bei einem Arbeitsspeicher von mehr als 1 GB circa 25\% des Arbeitsspeicher besitzen sollte \cite{PostgresC20.4:2024}. -Bei der Einstellung \textit{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. Und nur bei +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. -Der Speicher, der für eine Abfrage verwendet werden darf, wird über die Konfiguration \textit{work\_mem} gesteuert. +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 \textit{shared\_buffers} dividiert durch \textit{max\_connections} \citep{ConfigTo12:online}. -Sollte der 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 \textit{log\_temp\_files} auf 0 +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 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 -\textit{maintenance\_work\_mem} gesetzt. Dieser Wert sollte 5\% des verfügbaren Arbeitsspeicher entsprechen und größer -als \textit{work\_mem} sein. +Für die Wartungsaufgaben wie VACUUM oder dem Erstellen von Indexen wird die Begrenzung über die Einstellung +\texttt{maintenance\_work\_mem} gesetzt. Dieser Wert sollte 5\% des verfügbaren Arbeitsspeicher entsprechen und größer +als \texttt{work\_mem} sein. -Dann wird mit dem Systemtools, wie den Konsolenanwendungen \textit{htop} und \textit{free}, die Auslastung des Servers +Nachfolgend wird mit dem Systemtools, wie den Konsolenanwendungen \textit{htop} und \textit{free}, die Auslastung des Servers ü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 nicht die 70\% überschreiten, für kurze Spitzen wäre dies zulässig. Da sonst der +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. @@ -48,14 +48,14 @@ wodurch der aktuell nicht verwendete in die Page"=Datei ausgelagert wird. Hierdu diese Elemente drastisch. Die Zugriffsgeschwindigkeit, die Zugriffszeit sowie die Warteschlange an der Festplatte zeigt deren Belastungsgrenze auf. -Hierbei kann es mehrere Faktoren geben. Zum einem führt das Paging des Arbeitsspeicher zu erhöhten Zugriffen. Ein zu -klein gewählter Cache oder gar zu wenig Arbeitsspeicher erhöhen die Zugriffe auf die Festplatte, da weniger +In diesem Fall kann es mehrere Faktoren geben. Zum einem führt das Paging des Arbeitsspeicher zu erhöhten Zugriffen. +Ein zu klein gewählter Cache oder gar zu wenig Arbeitsspeicher erhöhen die Zugriffe auf die Festplatte, da weniger zwischengespeichert werden kann und daher diese Daten immer wieder direkt von der Festplatte geladen werden müssen. \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. @@ -71,8 +71,8 @@ abgelaufen ist. Ebenso wird nach Standorten sortiert, um zu ermitteln welchen Pe 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 \ref{lst:documentlist} gezeigt. Zusätzlich wird für jedes -dargestellte Dokument eine zusätzliche Abfrage durchgeführt, die in \ref{lst:documentlist_sub} zeigt, dass auch hier +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 weitere Relationen notwendig sind. \includecode[SQL]{chapters/thesis/chapter03_documentlist.sql}{lst:documentlist}{Generische Abfrage der Dokumentenliste} @@ -82,7 +82,7 @@ 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 Kapitel \ref{ch:basics} dargestellt, besteht die eigentliche Anwendung aus mehreren Schichten. Die +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. @@ -92,7 +92,7 @@ bereitgestellt, um die Daten Live vom Server verfolgen zu können. Zusätzlich w 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 -Klassen soll ermittelt und die Statistik"=Webseite um diese Daten erweitern. Um die Daten zu ermitteln, kann der +Klassen soll ermittelt werden und die Statistik"=Webseite um diese Daten erweitern. Um die Daten zu ermitteln, kann der Quellcode aus \ref{lst:persistence-context-statistics} verwendet werden. \begin{lstlisting}[language=Java,caption={Persistence"=Kontext Statistik},label=lst:persistence-context-statistics] @@ -112,11 +112,10 @@ 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. Hierfür wird eine \textit{Factory} eingebaut, die sich in die -Verarbeitung der Seiten einhängt, und damit die Zeiten für das Ermitteln der Daten, das Zusammensetzen und das -Render der Sicht aufgenommen werden können. Die Zeiten werden in die Log"=Datei des \textit{Glassfish}"=Servers -hinterlegt und durch das Skript ausgewertet. Somit ist es einfach aufzuzeigen, an welcher Stelle der größte Teil -der Verzögerung auftritt. +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 +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. 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 @@ -124,16 +123,16 @@ 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 -diese viel schneller abgefragt werden können. Zusätzlich werden die cached queries überprüft ob diese eine Verbesserung +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, das die Webseite immer vollständig gerendert vom Server an den Client übertragen wird. +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 -durchschnittliche Laufzeit ermittelt. Aufgrund der Speicherprobleme, werden auch die Speicherbenutzung des +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 Anhang \ref{ap:timing} zu finden. +gestartet wurde. Das zugehörige Script ist im \autoref{ap:timing} zu finden. diff --git a/chapters/thesis/chapter04.tex b/chapters/thesis/chapter04.tex index efe7e6c..75dd184 100644 --- a/chapters/thesis/chapter04.tex +++ b/chapters/thesis/chapter04.tex @@ -4,7 +4,7 @@ \label{ch:performance-checking} Für die Untersuchung der Performance"=Probleme sollten einige Vorbereitungen getroffen werden. Dazu gehören die -Konfigurationen des Servers und in welcher Art und Umfang Anpassungen für die Performance"=Messung an der Software +Konfigurationen des Servers und in welcher Art und Umfang Anpassungen für die Performance"=Messungen an der Software durchgeführt werden müssen. Hierbei ist zu beachten, dass die Anpassungen minimal sind, damit die Messung selbst nicht das Ergebnis verfälscht. Zum Abschluss wird noch auf die Untersuchung der Abfragen eingegangen, wie diese im PostgreSQL"=Server durchgeführt wird. @@ -34,22 +34,22 @@ Zusätzlich sollte noch die aktuelle Auslastung des Server überprüft werden. Als Server wird hier ein Redhat"=Server mit der Standard"=Konfiguration des PostgreSQL"=Server 10 verwendet. Daher wird von einer richtigen Konfiguration der Speicher ausgegangen. Ebenfalls wird davon ausgegangen, dass der -automatische Dienst für \textit{VACUUM} und \textit{ANALYZE} aktiv ist. Eine weitere Überprüfung des Servers ist nicht +automatische Dienst für \texttt{VACUUM} und \texttt{ANALYZE} aktiv ist. Eine weitere Überprüfung des Servers ist nicht möglich, da kein Zugang zum aktuellen Produktionsservers möglich ist. \section{Einbau und Aktivieren von Performance-Messung} \label{sec:performance-checking:performance-measure} Um eine Messung der Performance in der Webseite durchführen zu können, gibt es in \ac{JSF} die Möglichkeit, über eine -eigene Implementierung der Klasse \textbf{ViewDeclarationLanguageWrapper} sich in das generieren der Webseite -einzuhängen. Hierbei können die Funktionen für das Erstellen, des Bauen und das Rendern der Webseite überschrieben +eigene Implementierung der Klasse \texttt{ViewDeclarationLanguageWrapper} sich in das Generieren der Webseite +einzuhängen. Hierbei können die Funktionen für das Erstellen, das Bauen und das Rendern der Webseite überschrieben werden. In den überschriebenen Funktionen werden nun Laufzeiten gemessen und die ermittelten Zeiten mit einer Kennung in die Log"=Datei eingetragen. Durch die Kennung, können die Zeiten im Nachgang über ein Script ermittelt und ausgewertet werden. -Zusätzlich wird noch eine Implementierung der zugehörigen Factory"=Klasse \textbf{ViewDeclarationLanguageFactory} +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 \textbf{faces-config.xml} eingetragen, wie das in +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. \begin{lstlisting}[language=xml,caption={Einbindung Factory},label=lst:activate-factory] @@ -76,10 +76,10 @@ log_rotation_size = 100MB \end{lstlisting} Über die Konfiguration unter \autoref{lst:postgresql_logconf} wird definiert welche Werte protokolliert werden. Die -wichtigste Einstellung ist \textit{log\_min\_duration\_statement}, diese definiert ab welcher Laufzeit eine Abfrage +wichtigste Einstellung ist \texttt{log\_min\_duration\_statement}, diese definiert, ab welcher Laufzeit eine Abfrage protokolliert werden soll. Mit dem Wert 0 werden alle Abfragen protokolliert. Alle weitere Einstellungen sind so gesetzt, dass nicht unnötige Abfragen für die spätere Auswertung mit \textit{pgBadger} protokolliert werden. -Zusätzlich ist die Einstellung \textit{log\_temp\_files} auf 0 zu setzen. Dadurch werden alle erzeugten temporären +Zusätzlich ist die Einstellung \texttt{log\_temp\_files} auf 0 zu setzen, dadurch werden alle erzeugten temporären Dateien und ihre Größe ebenfalls protokolliert. Diese Dateien entstehen, wenn der temporäre Puffer für die Abfrage nicht ausreicht und die Zwischenergebnisse ausgelagert werden müssen. @@ -102,19 +102,19 @@ log_timezone = 'Europe/Berlin' \section{Prüfung von Abfragen} \label{sec:performance-checking:sql-query-checking} -Das untersuchen der protokollierten Abfragen auf Performance Optimierungen ist ein weiterer Bestandteil dieser Arbeit. -Das Schlüsselwort \textbf{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 dem die Knoten die -unterschiedlichen Zugriffsarten darstellt. Die Verbindung der Knoten und der Aufbau zeigt die Operationen, wie -etwas Joins, Aggregierung und Sortierung, und die Reihenfolgen der Abarbeitung. Zusätzlich sind auch Zwischenschritte, +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 +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 die geschätzten Anlauf"= und Gesamtkosten (\textit{costs}), die geschätzte Anzahl der Zeilen (\textit{rows}) und die geschätzte Breite jeder Zeile (\textit{width}). Der Wert von \textit{costs} wird bei übergeordneten Knoten summiert. -Bei der Option \textit{ANALYZE} wird die Abfrage ausgeführt und die echten Werte und Laufzeiten angezeigt. Ohne dieser, -wird nur der Plan erstellt und dargestellt. Durch \textit{VERBOSE} werden zusätzliche Informationen zum Abfrageplan -mit dargestellt und mit \textit{BUFFERS} werden die Informationen über die Nutzung der Caches mit dargestellt. Um an -Ende noch eine Zusammenfassung mit anzuhängen, gibt es die Option \textit{summary}. Eine vereinfachte Form des Aufrufs +Bei der Option \texttt{ANALYZE} wird die Abfrage ausgeführt und die echten Werte und Laufzeiten angezeigt. Ohne diese, +wird nur der Plan erstellt und dargestellt. Durch \texttt{VERBOSE} wird der Abfrageplan um zusätzliche Informationen +angereichert. Die Option \texttt{BUFFERS} erweitert die Informationen über die Nutzung der Caches. Für eine +Zusammenfassung am Ende des Abfrageplans, gibt es die Option \texttt{summary}. Eine vereinfachte Form des Aufrufs ist in \autoref{lst:explain-easy} dargestellt. \begin{lstlisting}[language=SQL,caption={Aufruf von EXPLAIN},label=lst:explain-easy] @@ -122,36 +122,38 @@ EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SUMMARY) select * from document; \end{lstlisting} -Die zwei bekanntesten Knotentypen sind \textit{Seq Scan} und \textit{Index Scan}. Beim \textit{Seq Scan} wird die -Tabelle Zeile für Zeile gelesen und wenn vorhanden nach den Bedingungen gefiltert, hierbei entsteht eine unsortierte -Liste, entsprechend sind die Startkosten niedrig. Die bessere Alternative ist der \textit{Index Scan}, bei dem der -Index nach den Kriterien durchsucht wird, was meist durch den Aufbau des Index als BTree (Multi"=Way Balanced Tree) -sehr schnell geht. +\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 +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öglichkeiten sind die Verwendung von Indexe. Diese sind aber mit bedacht zu wählen, da bei +Eine weitere Optimierungsmöglichkeit ist die Verwendung von Indexe. 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 -dessen Statistik muss regelmässig mit aktualisiert werden. Ebenfalls ist die Reihenfolge der Spalte in einem +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 aufwendige Abfragen zu optimieren, bietet der PostgreSQL noch die Möglichkeiten von -\textit{Materialized View}. Diese sind sehr ähnlich zu Sichten, speichern zusätzlich die Ergebnisse in einer -tabellenähnlichen Form ab. Somit sind die Zugriff auf diese Daten häufig performanter als die eigentliche Abfrage. -Die Performance wird durch die zusätzliche Aktualisierung des Datenbestand erkauft und muss daher abgewägt werden, -was sinnvoller ist. +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. +Daher muss abgewägt werden, ob die Performance-Verbesserung trotz der zusätzliche Aktualisierung des Datenbestandes +als sinnvoll erachtet werden kann. \mytodos{das doch wieder raus? oder nur das mit create statistics drin lassen} -Zusätzlich kann über die Systemtabelle \textit{pg\_statistic} oder die lesbarere Systemsicht \textit{pg\_stats} die +Zusätzlich kann über die Systemtabelle \texttt{pg\_statistic} oder die lesbarere Systemsicht \texttt{pg\_stats} die aktuelle statistischen Informationen über eine Tabelle und deren Spalten ermittelt werden. In dieser Tabelle werden -durch das \textit{ANALYZE} beziehungsweise \textit{VACUUM ANALYZE} Kommando die Informationen zum Anteil der -\textit{NULL}"=Werte (null\_frac), Durchschnittlichen Größe (avg\_width), unterschiedlicher Werte (n\_distinct) und +durch das \texttt{ANALYZE} beziehungsweise \texttt{VACUUM ANALYZE} Kommando die Informationen zum Anteil der +\texttt{NULL}"=Werte (null\_frac), Durchschnittlichen Größe (avg\_width), unterschiedlicher Werte (n\_distinct) und weitere gesammelt und für die Erstellung der Abfragepläne verwendet \citep{PostgreS39:online}. Diese Information sollte vor dem erstellen eines Index betrachtet werden. -Diese Informationen können noch durch das Kommando \textit{CREATE STATISTICS} erweitert werden, für einen besseren -Abfrageplan. Das aktivieren der zusätzlichen Statistiken sollten immer in Verbindung mit dem überprüfung des -Abfrageplans durchgeführt werden, um zu ermitteln ob die Anpassung zu einer Optimierung und keiner Verschlechterung -führt. +Diese Informationen können noch durch das Kommando \texttt{CREATE STATISTICS} erweitert werden, für einen besseren +Abfrageplan. Das Aktivieren der zusätzlichen Statistiken sollte immer in Verbindung mit der Überprüfung des +Abfrageplans durchgeführt werden, um zu ermitteln inwieweit die Anpassung zu einer Optimierung und keiner +Verschlechterung führt. diff --git a/chapters/thesis/chapter05.tex b/chapters/thesis/chapter05.tex index 46c7bcf..7fcb8f2 100644 --- a/chapters/thesis/chapter05.tex +++ b/chapters/thesis/chapter05.tex @@ -3,45 +3,45 @@ \chapter{Performance-Untersuchung der Anwendung} \label{ch:performance-investigation-application} -Nun werden die unterschiedlichen Schichten betrachtet und möglichen Performance"=Verbesserungen untersucht und deren +Nun werden die unterschiedlichen Schichten betrachtet und mögliche Performance"=Verbesserungen untersucht und deren Vor"= und Nachteile herausgearbeitet. -Für die Tests wird ein aktuelles Manjaro-System mit frisch installierten Payara als Serverhost und der IntelliJ IDEA +Für die Tests wird ein aktuelles Manjaro"=System mit frisch installierten Payara als Serverhost und der IntelliJ IDEA als Entwicklungsumgebung verwendet. Der Computer ist mit einer Intel CPU i7-12700K, 32 GB Arbeitsspeicher und einer SSD als Systemfestplatte ausgestattet. -Zur ersten Untersuchung und der Bestimmung der Basis-Linie, wurde das Script ohne eine Änderung an dem Code und der +Zur ersten Untersuchung und der Bestimmung der Basis-Linie, wurde das Script ohne eine Änderung am Code und der Konfiguration mehrfach aufgerufen. Hierbei hat sich gezeigt, dass der erste Aufruf nach dem Deployment circa 1500 ms gedauert hat. Die weiteren Aufrufe benötigen im Durchschnitt noch 600 ms. Beim achten Aufruf des Scripts hat der -Server nicht mehr reagiert und im Log ist ein OutOfMemoryError protokolliert worden. +Server nicht mehr reagiert und im Log ist ein \textit{OutOfMemoryError} protokolliert worden. -Nach einem Neustart des Servers, konnte das gleiche Verhalten wieder reproduziert werden. Daraufhin wurde das Test-Script -um die Anzeige der aktuellen Speicherverwendung des Payara-Servers erweitert und diese zeitgleich zu beobachten. Diese +Nach einem Neustart des Servers, konnte das gleiche Verhalten wieder reproduziert werden. Daraufhin wurde das Test"=Script +um die Anzeige der aktuellen Speicherverwendung des Payara"=Servers erweitert um diese zeitgleich zu beobachten. Diese Auswertung zeigte, dass der Server mit circa 1500 MB RSS Nutzung an seine Grenzen stößt. Diese Grenzen wurde durch die Konfigurationsänderung im Payara-Server von \texttt{-Xmx512m} auf \texttt{-Xmx4096m} nach oben verschoben. Nun werden -circa 60 Aufrufe des Scripts benötigt, damit der Server nicht mehr reagiert. Hierbei wird aber kein OutOfMemoryError +circa 60 Aufrufe des Scripts benötigt, damit der Server nicht mehr reagiert. Hierbei wird aber kein \textit{OutOfMemoryError} in der Log-Datei protokolliert und der Server verwendet nun circa 4700 MB RSS. Bei allen Tests war noch mehr als die 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 +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. 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 der \autoref{tbl:measure-without-cache}. +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 -ermitteln, auch hier gilt, dass weniger Aufrufe besser sind. Als letztes wird noch der verwendete Arbeitsspeicher +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 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. -Als Grundlage für die Vergleiche wurden eine Messung durchgeführt, bei der alle Caches deaktiviert wurden und keine +Als Grundlage für die Vergleiche wurde eine Messung durchgeführt, bei welcher alle Caches deaktiviert wurden und keine Änderung am Code vorgenommen wurde. Das Ergebnis dieser Messung ist in \autoref{tbl:measure-without-cache} zu finden. -Diese zeigen auch direkt ein erwartetes Ergebnis, dass der erste Aufruf bedeutend länger dauert als die Nachfolgenden. +Diese zeigen auch direkt ein zu erwartendes Ergebnis, dass der erste Aufruf bedeutend länger dauert als die Nachfolgenden. Ebenfalls sieht man eindeutig, dass die Anzahl der Anfragen nach dem ersten Aufruf immer die gleiche Anzahl besitzen. -Der Speicherbedarf steigt auch relative gleichmässig, was nicht recht ins Bild passt, da hier keine Objekte im Cache +Der Speicherbedarf steigt relative gleichmässig, was nicht recht ins Bild passt, da hier keine Objekte im Cache gehalten werden sollten. \begin{table}[!h] @@ -62,7 +62,7 @@ gehalten werden sollten. \label{tbl:measure-without-cache} \end{table} -Vor jedem weiteren Test-Lauf wurde die Domain beendet und komplett neugestartet, um mit einer frischen Instanz zu +Vor jedem weiteren Test"=Lauf wird die Domain beendet und komplett neugestartet, um mit einer frischen Instanz zu beginnen. Hierbei ist aufgefallen, dass fast immer 62 Abfragen zur Startup-Phase dazugehört haben, unabhängig von den konfigurierten Cache Einstellungen. Einige dieser Abfragen sind durch das Erstellen der \textit{Materialized View} \textit{searchreference} und \textit{searchfulltext} erklärbar. Zusätzlich ist noch ein zyklischer Dienst @@ -71,22 +71,22 @@ und entsprechend einige Abfragen an die Datenbank absetzt. Da weder die Sichten benötigt werden, wurde der Dienst und das Erstellen im Code für die weiteren Tests deaktiviert. Da die Abfragezeiten auf der Datenbank zu gering waren, um eine Verbesserung feststellen zu können, wurde für den -PostgreSQL und den Payara-Server ein Docker-Container erzeugt und diese limitiert. Die Konfiguration ist im +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 neue Messungen. Für den Speicherbedarf wird nun nicht mehr der benutzte +Mit dem neuen Aufbau ergeben sich nun 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. -Für die Ausführungszeiten der SQL-Abfragen wurden nur die sechs Abfragen für die Darstellung der Tabelle beachtet. +Für die Ausführungszeiten der \ac{SQL}"=Abfragen wurden nur die sechs Abfragen für die Darstellung der Tabelle beachtet. Hierzu zählt die Hauptabfrage der Dokumenten"=-Tabelle, die Ermittlung des letzten und ersten Eintrags in der Tabelle, 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. +zu laden, und in die Java"=Objekte umzuformen. \begin{table}[h] \centering @@ -112,11 +112,11 @@ zu laden, und in die Java-Objekte umzuformen. \section{Caching im OpenJPA} \label{sec:performance-investigation-application:caching-openjpa} -Die Cache-Einstellung von OpenJPA werden über die zwei Einstellungen \texttt{openjpa.DataCache} und +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 Elementen im Cache gesteuert werden. Wird diese Anzahl erreicht, dann werden zufällige -Objekte aus dem Cache entfernt und in eine SoftReferenceMap übertragen. Bei der Berechnung der Anzahl der Element werden +\textit{CacheSize} die Anzahl der Elemente im Cache gesteuert werden. Wird diese Anzahl erreicht, dann 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. Die Anzahl der Soft References kann ebenfalls über eine Einstellung gesteuert werden. Hierfür wird die Anzahl der @@ -153,7 +153,7 @@ wachsenden Speicherbedarfs nur nicht erklärt werden. \label{tbl:measure-ojpa-active} \end{table} -Bei einer erhöhten Cache-Größe, von 1000 auf 10000, zeigt sich auf den ersten Blick ein noch besseres Bild ab, wie in +Bei einer erhöhten Cache"=Größe, von 1000 auf 10000, zeigt sich auf den ersten Blick ein noch besseres Bild ab, wie in \autoref{tbl:measure-ojpa-active-bigger} ersichtlich ist. Der erste Aufruf entspricht der Laufzeit mit geringerer Cache"=Größe, aber schon die Anfragen an die Datenbank gehen drastisch zurück. Bei den weiteren Aufrufen werden im Schnitt nun nur noch 6 Anfragen pro Seitenaufruf an die Datenbank gestellt, wodurch die Laufzeit im Schnitt nochmal @@ -213,11 +213,11 @@ der Objekte den Cache übersteigt, fällt die Verbesserung geringer aus. \section{Cached Queries} \label{sec:performance-investigation-application:cached-query} -Über die Einstellung \textit{openjpa.""jdbc.""QuerySQLCache} wird der Cache für abfragen aktiviert. Hierbei können +Über die Einstellung \textit{openjpa.""jdbc.""QuerySQLCache} wird der Cache für Abfragen aktiviert. Hierbei können Abfragen angeben werden, die aus dem Cache ausgeschlossen werden. Der QueryCache wiederrum beachtet aber nur Abfragen -die keine Parameter verwenden. Das sieht man auch entsprechend der Auswertung der Aufrufe in der -\autoref{tbl:measure-cached-queries}, dass hier keine Veränderung der Aufrufzeiten stattgefunden hat. Gleich ob man -mit \ac{JPQL} oder mit der Criteria API abfragt. +die keine Parameter verwenden. Das sieht man auch entsprechend der Auswertung der Aufrufe in +\autoref{tbl:measure-cached-queries}, dass hier keine Veränderung der Aufrufzeiten stattgefunden hat, gleich ob +mit \ac{JPQL} oder Criteria API abfragt wird. % document, documentaddresseeperson, first/last, documentcoauthorperson, count und documentfacsimile \begin{table}[h!] @@ -247,7 +247,7 @@ mit \ac{JPQL} oder mit der Criteria API abfragt. 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. Zusätzlich dazu sind die Konfiguration \textit{openjpa.""QueryCache}, \textit{openjpa.""DataCache} und -\textit{openjpa.""DataCacheManager} auf \textit{ehcache} anzupassen. Anhand der Annotation \textbf{@DataCache} kann +\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 @@ -255,10 +255,10 @@ Cache"=Manager aktiviert werden, dieser kann entweder durch Code programmiert we in der \textit{ehcache.xml}. Anhand der Auswertung von \ref{tbl:measure-ehcache-active} sieht man, dass der Ehcache einen starke Performance -Verbesserung aufbringt. Über die Performance"=Statistik"=Webseite kann beobachtet werden, dass bei gleichen Aufruf +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. Zusätzlich zeigt sich, -das sich die Abfragezeiten in der Datenbank nur gering verkürzt wurden, aber die Laufzeit der Webseite sich starkt +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 verbessert hat. Dies lässt auch hier den Schluss zu, dass die Erstellung der Objekte im OpenJPA die meiste Zeit benötigt. @@ -288,13 +288,13 @@ benötigt. \section{Caching in EJB} \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 -Größen des Pools definiert werden. Ebenso wird an dieser Stelle die maximale Größe des Caches und die Größe der +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 +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. Und es ist ersichtlich, dass die Anzahl der Datenbankabfragen nicht reduziert +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 den Controller bereitgestellt werden. Die Objekt selbst werden nicht im \ac{EJB}"=Cache hinterlegt. @@ -316,7 +316,7 @@ den Controller bereitgestellt werden. Die Objekt selbst werden nicht im \ac{EJB} \hline \end{tabular} } - \caption{Messung mit \ac{EJB}-Cache} + \caption{Messung mit EJB"=Cache} \label{tbl:measure-ejb-cache-active} \end{table} @@ -324,7 +324,7 @@ den Controller bereitgestellt werden. Die Objekt selbst werden nicht im \ac{EJB} \label{sec:performance-investigation-application:query-jpql} Für die \ac{JPQL} wird ein \ac{SQL} ähnlicher Syntax verwendet um die Abfragen an die Datenbank durchzuführen. Für die -Dokumentenliste wird der Code aus dem \autoref{lst:jpql-document-list-jpql} verwendet. Die Namen mit vorangestellten +Dokumentenliste wird der Code aus \autoref{lst:jpql-document-list-jpql} verwendet. Die Namen mit vorangestellten Doppelpunkt sind Übergabevariablen. \begin{lstlisting}[language=Java,caption={JPQL Dokumentenliste},label=lst:jpql-document-list-jpql] @@ -359,45 +359,46 @@ if(myResultList != null && !myResultList.isEmpty()) { Da dieser Code direkt so aus dem Projekt kommt, wird hierfür keine gesonderte Zeitmessung durchgeführt, da diese der Messung aus \autoref{tbl:measure-without-cache} entspricht. -Für die Optimierung wurden noch zusätzlich die Hints \textit{openjpa.""hint.""OptimizeResultCount}, -\textit{javax.""persistence.""query.""fetchSize} und \textit{openjpa.""FetchPlan.""FetchBatchSize} gesetzt. Hierbei +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. -Ebenso bringt der Hint \textit{openjpa.""FetchPlan.""ReadLockMode} auch keinen Unterschied bei der Geschwindigkeit. -Hierbei ist erklärbar, da im Standard bei einer reinen Selektion eine Lesesperre aktiv sein muss. -Bei \textit{openjpa.""FetchPlan.""Isolation} wird gesteuert, auf welche Sperren beim laden geachtet wird. Damit könnte -man zwar schreibsperren umgehen, und würde damit die Anfrage nicht mehr blockieren lassen, aber es führt unweigerlich -zu sogenannten \glqq Dirty"=Reads\grqq, wodurch die Ausgabe verfälscht werden könnte. Daher ist diese Einstellung sehr +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. +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 mit Vorsicht zu verwenden. -Mit dem Hint \textit{openjpa.""FetchPlan.""EagerFetchMode} wird definiert, wie zusammengehörige Objekte abgefragt werden. +Mit dem Hint \texttt{openjpa.""FetchPlan.""EagerFetchMode} wird definiert, wie zusammengehörige Objekte abgefragt werden. Bei dem Wert \textit{none} werden nur die Basis"=Daten abgefragt und jedes weitere Objekt wird in einem eigenen -Statement abgefragt. Mit \textit{join} wird definiert, dass abhängige Objekte die als \glqq to-one\grqq"=Relation +Statement abgefragt. Mit \textit{join} wird definiert, dass abhängige Objekte die als >>to-one<<"=Relation definiert sind, in der Abfrage über einen Join verknüpft und damit direkt mitgeladen werden. Bei reinen -\glqq to-one\grqq"=Relation funktioniert das rekursive und spart sich damit einige einzelne Abfragen. -Bei der Einstellung \textit{parallel} wird für zwar für jedes abhängigen Objektdefinition eine Abfrage durchgeführt, -aber bei dieser wird der Einstieg über das Hauptobjekt durchgeführt. 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 WHERE"=Abfrage nochmal durchgeführt und um -die JOINS ergänzt, um die Daten der Unterobjekte zu ermitteln. -Mit dem Hint \textit{openjpa.""FetchPlan.""SubclassFetchMode} ist die Konfiguration für Unterklassen definiert. Die -Möglichkeiten entsprechen der vom \textit{openjpa.""FetchPlan.""EagerFetchMode}. +>>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 +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}. Beim Umstellen der 2 Hints auf \textit{parallel} wird die Bearbeitungszeit fast halbiert und Anzahl der Datenbankaufrufe wurde fast geviertelt. Dies zeigt, dass die einzelnen Aufrufe je Dokument aufwendiger sind, als eine komplette Abfrage der abhängigen Daten und das zusammensetzen in der OpenJPA-Schicht. -Der letzte Hint \textit{openjpa.""FetchPlan.""MaxFetchDepth} schränkt die rekursive Tiefe ein, für die abhängige +Der letzte Hint \texttt{openjpa.""FetchPlan.""MaxFetchDepth} schränkt die rekursive Tiefe ein, für die abhängige Objekte mitgeladen werden. Lediglich auf Grund fehlender Datenbestände wird die Abfrage beschleunigt. \section{Abfragen Criteria API} \label{sec:performance-investigation-application:query-criteria-api} -Für die Criteria API wird die Abfrage nicht in einem SQL-Dialekt beschreiben. Hierbei werden über Attribute die +Für die Criteria API wird die Abfrage nicht in einem SQL-Dialekt beschreiben, hierbei werden über Attribute die Verlinkung zur Datenbank durchgeführt. An der Klasse selbst wird der Tabellenname definiert und an den Attributen die -Spaltennamen. Um die Anfrage durchführen muss nun nur noch Datenklasse angegeben werden und mit den Parametern +Spaltennamen. Um die Anfrage durchzuführen muss nun nur noch die Datenklasse angegeben und mit den Parametern versorgt werden, wie es in \autoref{lst:criteria-api} gezeigt wird. \begin{lstlisting}[language=Java,caption={Criteria API Dokumentenliste},label=lst:criteria-api] @@ -427,7 +428,7 @@ 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 anschaut, sieht man auch, dass die zusammengesetzten +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. \begin{table}[h!] @@ -456,21 +457,21 @@ Implementierung ohne bedenken gegeneinander ausgetauscht werden, und die verwend einfacher umzusetzen ist. Bei den Hints ist es das gleiche wie bei \ac{JPQL}. Auch hier haben die meisten Hints keinen merkbaren Einfluss. Die -Einstellung \textit{openjpa.""FetchPlan.""EagerFetchMode} liefert auch hier Optimierungen, wenn der Wert auf +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. \section{Materialized Views} \label{sec:performance-investigation-application:materialized-views} -\textit{Materialized Views} sind Sichten in der Datenbank, die beim erstellen der Sicht den aktuellen Zustand ermitteln -und Zwischenspeichern. Somit wird beim Zugriff auf diese Sichten, nicht die hinterlegte Abfrage ausgeführt, sondern auf +\textit{Materialized Views} sind Sichten in der Datenbank, die beim Erstellen der Sicht den aktuellen Zustand ermitteln +und zwischenspeichern. Somit wird beim Zugriff auf diese Sichten, nicht die hinterlegte Abfrage ausgeführt, sondern auf die gespeicherten Daten zugegriffen. Dies ist gerade bei vielen Joins von Vorteil. Zusätzlich können auf solchen Sichten auch Indexe erstellt werden, um noch effektiver die Abfragen bearbeiten zu können. Der größte Nachteil dieser Sichten ist, dass sie zyklisch oder bei Datenänderungen aktualisiert werden müssen, sonst läuft der Datenbestand der Sicht und der zugrundeliegenden Abfrage auseinander. Da die Hauptarbeiten auf der Webseite -die Abfrage der Daten ist, und nicht das editieren, kann dieser Nachteil bei entsprechender Optimierung ignoriert werden. +die Abfrage der Daten ist, und nicht das Editieren, kann dieser Nachteil bei entsprechender Optimierung ignoriert werden. In diesem Test wurde die aktuelle Implementierung aus dem Wedekind"=Projekt der \textit{Materialized View} inklusive der Trigger und der \textit{SearchDocument}"=Klasse übernommen \citep{Dokument53:online}. Wie in @@ -586,7 +587,7 @@ CREATE INDEX idx_searchdocument_documentcategory \end{lstlisting} Für die Datenermittlung wurden die notwendigen Teile aus dem Wedekind"=Projekt kopiert. Bei der Darstellung wurden die -vorhanden Elemente die die Liste der Dokumente anzeigt kopiert und auf die \textit{SearchDocument}"=Klasse angepasst. +vorhanden Elemente, welche die Liste der Dokumente anzeigt, kopiert und auf die \texttt{SearchDocument}"=Klasse angepasst. % document, first/last, documentaddresseeperson, documentcoauthorperson, documentfacsimile und count % document, count, first/last @@ -614,13 +615,13 @@ vorhanden Elemente die die Liste der Dokumente anzeigt kopiert und auf die \text 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 der Speicheranstieg weniger stark aus. Die Verbesserung der Aufrufzeiten lässt sich zusätzlich erklären, dass hier nun -nur noch vier statt der 6 Abfragen an die Datenbank gestellt werden, da die Einzelabfragen für die Adressen der +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 wurde. Da die Sicht nun explizit für dies Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die +benötigt wurden. Da die Sicht nun explizit für dies 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. +\autoref{lst:sql-materialized-view-ext} und das Entfernen der Parameter aus dem SQL"=Anfragen im Java"=Code. \begin{lstlisting}[language=SQL,caption={SQL Materialized View Erweiterung},label=lst:sql-materialized-view-ext] WHERE d.validuntil > NOW() @@ -628,7 +629,7 @@ AND d.ispublishedindb = true; \end{lstlisting} Nach dem Anpassungen haben sich dann die Werte aus \autoref{tbl:measure-materialized-view-ext} ergeben. Diese Werte -zeigen nur minimale Unterschiede in den Zeiten, was auf Messtoleranzen zurückzuführen ist. +zeigen nur minimale Unterschiede in den Zeiten, diese sind auf Messtoleranzen zurückzuführen. \begin{table}[h!] \centering @@ -651,34 +652,35 @@ zeigen nur minimale Unterschiede in den Zeiten, was auf Messtoleranzen zurückzu \label{tbl:measure-materialized-view-ext} \end{table} -Da bei der \textit{Materialized View} das laden der Daten und das wandeln in die Java"=Objekte getrennt programmiert +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 -\textit{map}"=Aufruf und der \textit{map}"=Aufruf gemessen. Für den ersten Aufruf, wurde ein \textit{SearchDocument} -Objekt erzeugt und immer diese Objekt zurückgegeben. Damit wurde erst mal überprüft, wie lange das ermitteln der Daten -und das durcharbeiten der Ergebnisse bestimmt. Hierbei lagen die Zeiten bei circa 1 ms für das reine Datenladen und 3 ms -für den Aufruf der \textit{map}"=Funktion. Sowie innerhalb der \textit{map}"=Funktion pro Eintrag ein Objekt -erzeugt, noch ohne eine Konvertierung der ermittelten Daten in das Objekt, steigt die Laufzeit schon auf 54 ms. -Wenn man nun noch die Konvertierung der Daten wieder einbaut, steigt die Laufzeit nochmal auf nun 82 ms. -Dies zeigt, alleine das erzeugen der Objekt und der Json"=Parse Aufruf kostet die meiste Zeit. +\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} +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. +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 \textit{openjpa.""FetchPlan.""FetchBatchSize} kann die Abfrage enorm verschlechtern. Wenn +Bei der Verwendung des Hints \texttt{openjpa.""FetchPlan.""FetchBatchSize} kann 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 \textit{map}"=Funktion wird dadurch verlängert. +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 +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. -Dies ist dadurch erklärbar, da keine Objekte durch das OpenJPA"=Framework erstellt werden, sondern erst in der -\textit{map}"=Funktion des eigenen Codes und daher wird der Cache nicht genutzt. +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. -Wie schon ermittelt, benötigt das erstellen der Objekte den Großteil der Zeit für die Datenermittlung. Aufgrund dessen -wurde die übernommen \textit{SearchDocument}"=Klasse nochmal genauer betrachtet. Beim erstellen, werden die +Wie schon ermittelt, benötigt das Erstellen der Objekte den Großteil der Zeit für die Datenermittlung. Auf Grund dessen +wurde die übernommene \texttt{SearchDocument}"=Klasse abermals genauer betrachtet. Beim Erstellen werden die \textit{Json}"=Daten direkt in Java"=Objekte gewandelt. Im ersten Schritt wird die Parse"=Funktion entfernt und die Seite nochmals aufgerufen. Durch diese Umstellung fällt die Laufzeit der Datenermittlung auf circa 4 ms ab. Nun muss -noch geprüft werden, welche Zeit nun der Client zum parsen der \textit{Json}"=Daten benötigt. Hierfür werden die -Daten in einem versteckten \textbf{span}"=Element hinterlegt, wie es im \autoref{lst:jsf-datatable-json} zu sehen ist. +noch überprüft werden, welche Zeit nun der Client zum parsen der \textit{Json}"=Daten benötigt. Hierfür werden die +Daten in einem versteckten \texttt{span}"=Element hinterlegt, wie es im \autoref{lst:jsf-datatable-json} zu sehen ist. Die hinterlegte \textit{CSS}"=Klasse ist zum auffinden der Elemente für den späteren Javascript. Das -\textbf{ajax}"=Element im Beispiel ist notwendig, damit bei einem Seitenwechsel die gleiche Interpreter"=Funktion für +\textit{ajax}"=Element im Beispiel ist notwendig, damit bei einem Seitenwechsel die gleiche Interpreter"=Funktion für die \textit{Json}"=Daten aufgerufen wird, wie beim laden der Webseite. \begin{lstlisting}[language=xml,caption={DataTable mit Json},label=lst:jsf-datatable-json] @@ -694,10 +696,10 @@ 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 ie übertragenen +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} -ermittelt erst alle versteckten Elemente, parsed den Inhalt und erstellt neue \textit{HTML}"=Elemente mit dem -darzustellenden Inhalt. Zusätzlich wird noch eine Zeitmessung mit eingebaut, um die Laufzeit am Client für das Rendern +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. \begin{lstlisting}[language=javascript,caption={Wandeln von Json nach Html},label=lst:jsf-datatable-json-convert] @@ -741,16 +743,16 @@ $(document).ready(function() { }); \end{lstlisting} -Da nun am Client Code ausgeführt wird, nachdem die Daten übertragen wurden, kann nicht mehr alles über das Script +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. Dies bedeutet addiert kommt man mit dieser -Lösung auf eine kürzere Laufzeit und weniger Last am Server. +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} \section{Optimierung der Abfrage} \label{sec:performance-investigation-application:optimizing-query} -Für die Optimierung der Abfrage werden diese zuerst mit \textit{explain}, wie in \autoref{lst:explain-diagnostic} -dargestellt, untersuchen. Für die einfachere Diagnose, wird der erstellte Plan mit Hilfe von +Für die Optimierung der Abfragen werden diese zuerst mit \texttt{EXPLAIN}, wie in \autoref{lst:explain-diagnostic} +dargestellt, untersucht. Für die einfachere Diagnose, wird der erstellte Plan mit Hilfe von \textit{Postgres Explain Visualizer 2} (\url{https://github.com/dalibo/pev2}) visualisiert. \begin{lstlisting}[language=SQL,caption={Explain für Diagnose},label=lst:explain-diagnostic] @@ -773,7 +775,7 @@ limit 400; Die erstellte Visualisierung der Abfrage ist in \autoref{fig:explain-visualize} zu sehen. In der Visualisierung wurde die Darstellung der Kosten gewählt, da ein Vergleich auf Basis der Zeit sehr schwierig ist und von äußeren Faktoren -abhängt, wie zum Beispiel dem Cache. Die Kosten sind stabiler und hängen in erster Linie vom Datenbestand ab. +abhängt, wie zum Beispiel dem Cache. Die Kosten sind stabiler und hängen in erster Linie von der Art des Datenbestandes ab. \begin{figure}[h!] \includegraphics[width=\linewidth]{gfx/chapter05_ExplainVisualize.png} @@ -782,19 +784,19 @@ abhängt, wie zum Beispiel dem Cache. Die Kosten sind stabiler und hängen in er \end{figure} In der Graphik ist zu sehen, dass zum einen die Hauptkosten im untersten Knoten \textit{Seq Scan} und einen der -obersten Knoten dem \textit{HashAggregate} liegen. Zusätzlich sieht man anhand der stärke von den Verbindungslinien der -Knoten, dass die Menge der Datensätze enorm hoch ist und dieser sich bis zum obersten Knoten durchzieht. Dies +obersten Knoten dem \textit{HashAggregate} liegen. Zusätzlich sieht man anhand der Stärke von den Verbindungslinien der +Knoten, dass die Menge der Datensätze enorm hoch ist und diese sich bis zum obersten Knoten durchziehen. Dies bedeutet, dass die Einschränkung des Datenbestandes erst am Ende der Abfrage durchgeführt wird und diesbezüglich die Dauer der Abfrage linear mit den Inhalt der \textit{document}"=Tabelle zusammenhängt. Des Weiteren wird für keine -Tabelle ein \textit{Index Scan} verwendet, sondern immer mit einem \textit{Seq Scan} gearbeitet, da durch das ermitteln -des kompletten Datenbestandes der Optimizer entscheidet, dass der komplette Scan der Tabelle kostengünstiger ist, als +Tabelle ein \textit{Index Scan} verwendet, sondern immer mit einem \textit{Seq Scan} gearbeitet, da durch das Ermitteln +des kompletten Datenbestandes der Optimizer entscheidet, ob der komplette Scan der Tabelle kostengünstiger ist, als die Verwendung eines der vorhandenen Indexe. Dies kann durch den Befehl \lstinline[language=SQL]|SET enable_seqscan = off| -sehr einfach verifiziert werden. Damit wird die Verwendung von \textit{Seq Scan} deaktiviert und es wird dann ein +sehr einfach verifiziert werden. Damit wird die Verwendung von \textit{Seq Scan} deaktiviert und es wird anschließend ein \textit{Index Scan} verwendet. Wenn man nun beide Pläne vergleicht sieht man die Erhöhung der Kosten bei der Verwendung von \textit{Index Scan}. Die beste Optimierung hierbei ist, die Menge der Datensätze so früh wie möglich einzuschränken. Da die Verwendung von -\textit{order by} innerhalb eines Sub"=Selects nicht erlaubt ist, verwenden wir hierfür eine \textit{Common Table +\texttt{order by} innerhalb eines Sub"=Selects nicht erlaubt ist, verwenden wir hierfür eine \textit{Common Table Expression}, wie es in \autoref{lst:explain-optimize-cte} zu sehen ist. Zusätzlich wurde noch ein Index auf der \textit{document}"=Tabelle für die Spalten der Bedingung und der Sortierung gesetzt, wie in \autoref{lst:explain-optimize-cte-idx} zur sehen, damit in der \textit{Common Table Expression} nur der Index verwendet @@ -821,9 +823,9 @@ create index idx_document_with_stmt on document using btree , startday desc, id ); \end{lstlisting} -Mit diesen Umstellungen erkennt man nun, dass die Kosten entsprechend gefallen sind. Ebenfalls konnten die Laufzeit um +Mit diesen Umstellungen erkennt man, dass die Kosten entsprechend gefallen sind. Ebenfalls konnten die Laufzeit um mehr als den Faktor drei reduziert werden. Die Optimierung ist in \autoref{fig:explain-visualize-with} sehr deutlich -an dein dünneren Verbindungslinien zwischen den Knoten und der Umstellung von einigen \textit{Seq Scan} zu +an den dünneren Verbindungslinien zwischen den Knoten und der Umstellung von einigen \textit{Seq Scan} zu \textit{Index Scan} ersichtlich. Zeitgleich ist auch der teure \textit{HashAggregate} nicht mehr im Abfrageplan vorhanden. @@ -834,7 +836,7 @@ vorhanden. \end{figure} Bei der Untersuchung der Abfrage zur \textit{Materialized View} ist direkt herausgekommen, dass hier keine Optimierung -mehr möglich ist, da durch die definierten Index bei den aktuell möglichen Sortierkriterien direkt ein +mehr möglich ist, da durch die definierten Indexe bei den aktuell möglichen Sortierkriterien direkt ein \textit{Index Scan} verwendet wird. Dies ist durch eine Überprüfung der Abfragepläne beweisbar, für diesen Fall wird die Abfrage aus \autoref{lst:explain-search-document} verwendet. @@ -850,10 +852,10 @@ limit 400; \end{lstlisting} Der dazugehörige Abfrageplan ist in \autoref{lst:explain-search-document-output} zu sehen, hierbei ist die erste -Ausgabe mit dem erstellten Index und vor der zweiten Ausgabe wurde der Index deaktiviert. Anhand der Ausgabe ist zu +Ausgabe mit dem erstellten Index. Vor der zweiten Ausgabe wurde dieser Index deaktiviert. Anhand der Ausgabe ist zu sehen, dass bei der Verwendung des Index weniger Operation notwendig sind und damit auch die teure Sortierung -eingespart werden konnte. Dies liegt daran, dass der Index entsprechend des Sortierkriterien definiert wurde Und -somit es möglich ist, direkt in den Index die Elemente in der richtigen Reihenfolge zu ermitteln. +eingespart werden konnte. Dies liegt daran, dass der Index entsprechend des Sortierkriterien definiert wurde und +somit ist es möglich, direkt in dem Index die Elemente in der richtigen Reihenfolge zu ermitteln. Somit ist durch den Index der schnellstmögliche Zugriff gegeben. \begin{lstlisting}[basicstyle=\scriptsize,caption={aa},label=lst:explain-search-document-output] diff --git a/chapters/thesis/chapter06.tex b/chapters/thesis/chapter06.tex index 70fc9bf..dbad87b 100644 --- a/chapters/thesis/chapter06.tex +++ b/chapters/thesis/chapter06.tex @@ -5,10 +5,10 @@ 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. +der Effektivität mit beachtet. \mytodos{verena} 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 welchen Umfang +Caches, bei denen eine Größe angebbar ist, wurde zusätzlich mit der Anzahl variiert, um zu ermitteln in welchem Umfang sich diese auswirkt. Des Weiteren wird die Art der Programmierung für die Abfragen betrachtet, ob signifikante Unterschiede in der Performance und der Abarbeitung erkennbar sind. Als weiteren Punkt werden die Abfragen an die Datenbank untersucht, um zu ermitteln ob diese durch Umstellung verbessert werden können. Abschließend werden die @@ -31,14 +31,14 @@ 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. Dies ist in diesem Fall nicht anwendbar, da nicht nur 1:n Beziehungen vorhanden sind, sondern auch auch n:m Beziehungen. -Dadurch würden sich die Anzahl der Dokumentenliste erhöhen. Eine weitere Möglichkeit wäre es, die Duplikate auf der +Dadurch würde sich die Anzahl der Dokumentenliste erhöhen. Eine weitere Möglichkeit wäre es, die Duplikate auf der Serverseite zusammenzuführen. \section{Statische Webseiten} \label{sec:evaluation:static-website} Eine Umstellung der Dokumentenliste in statische Webseite, würde die Zugriffszeiten sehr verkürzen. Darüber hinaus -funktionieren in statischen Webseiten aber keine Suchen oder eine Sortierungen. Die Sortierung könnte durch das Erstellen +funktionieren in statischen Webseiten aber keine Suchen oder Sortierungen. Die Sortierung könnte durch das Erstellen von statischen Seiten aller Möglichkeiten der Sortierung emuliert werden, diese würde den notwendigen Speicherbedarf der Webseite vervielfachen. Für die Suchanfragen ist dies nicht mehr möglich, da nicht alle Suchanfragen vorher definiert werden können. @@ -65,9 +65,9 @@ die notwendige Rechenleistung fehlt, um die Webseite in annehmbarer Zeit darzust Die Aufteilung eines großen Datenbestandes in mehrere einzelne Seiten, ist eine der wenige Optimierungsmöglichkeiten in der JSF"=Ebene. Dieser Einbau optimiert direkt an mehreren Stellen, dazu gehört die kleinere Datenmenge die vom -Datenbankserver geladen wird. Ebenso wird entsprechend weniger Zeit benötigt um die View zu erstellen und die zum -Client übertragene Datenmenge ist auch geringer. Dadurch benötigt die Seite auf dem Client auch weniger Zeit zum -rendern. +Datenbankserver geladen wird. Ebenso wird entsprechend weniger Zeit benötigt um die View zu erstellen, +gleichzeitig wir die übertragene Datenmenge an den Client reduziert. Dadurch benötigt die Seite auf dem Client weniger +Zeit zum rendern. Da das Paging für den Fall der Dokumentenliste implementiert ist, gibt es hier keine weiteren offensichtliche Optimierungsmöglichkeiten. @@ -85,7 +85,7 @@ Das Entfernen der Objekte kann zwar umgangen werden, indem die häufig abgefragt 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 -Grenzwert aufbaut und dann nicht mehr entleeren wird. Gerade bei kleiner dimensionierten Servern stellt dies ein +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. Dies ist der Grund warum diese Anfragen in diesem Cache nicht gespeichert werden. +werden. Aus diesem Grund werden die Anfragen in diesem Cache nicht gespeichert werden. Dadurch ist dieser Cache für eine Performance"=Verbesserung in dem Fall der Dokumentenliste nicht anwendbar. @@ -129,7 +129,7 @@ des OpenJPA Framework liegen muss. Durch die effizienter Verwendung des Speichers, ist der Ehcache die bessere Alternative zum OpenJPA"=Cache. Dieser ist auch schon für kleinere Serverkonfigurationen gut verwendbar. Hierbei ist nur abzuwägen, mit welcher Größe der Cache -bereitgestellt werden kann, was direkt am verfügbaren Arbeitsspeicher abhängt. +bereitgestellt werden kann, dies hängt direkt vom verfügbaren Arbeitsspeicher ab. \section{Caching in EJB} \label{sec:evaluation:ejb} @@ -154,7 +154,7 @@ von OptimizeResultCount, der FetchSize sowie der FetchBatchSize hilft dem Framew 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 -ermittelt werden. Bei Umstellung auf \textit{parallel} konnte für die Ermittlung der Dokumente einiges an Performance gewonnen +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. @@ -164,7 +164,7 @@ Auf Grund dessen ist die Entscheidung der Technik für die Performance irrelevan 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 -ausgegangen werden kann. Gerade bei ein größeren Anzahl lohnt es sich den Hint auf \textit{parallel} zu setzen. +ausgegangen werden kann. Gerade bei einer größeren Anzahl lohnt es sich den Hint auf \textit{parallel} zu setzen. Gleiches gilt dem Hint SubclassFetchMode, dieser steuert dimensionierte Abfragen im Falle von abgeleiteten Klassen. \section{Materialized View} @@ -173,9 +173,9 @@ 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 -zurückgegeben. Der größte Nachteil der \textit{Materialized View} ist, das bei einer Änderung an den Quelldaten die +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, noch selten Änderungen erfahren. Die Recherche über den Datenbestand die größte Zeit +Briefe einmalig eingepflegt wurden, nur noch selten Änderungen erfahren. Die Recherche über den Datenbestand die größte Zeit gewidmet wird. Ein weiterer Nachteil der \textit{Materialized View} ist die doppelte Speicherung der Daten, da die Daten für die Sicht @@ -185,12 +185,12 @@ die Faksimile, sind nicht in dieser Sicht enthalten und werden erst beim Anzeige Zusätzlich ist zu beachten, dass bei der Verwendung eines Caches die Daten ebenfalls doppelt gehalten werden und in den meisten Fällen im Arbeitsspeicher gehalten werden. -Eine weitere Optimierung, welche durch die \textit{Materialized View} entstanden ist, ist die direkte integration der +Eine weitere Optimierung, welche durch die \textit{Materialized View} entstanden ist, ist die direkte Integration der Autoren, der Koautoren und der Adressen im \textit{Json}"=Format. Durch diese aus dem Wedekind-Projekt übernommene Idee konnten schon viele zusätzliche Abfragen eingespart werden, da diese nicht mehr durch OpenJPA nach der Hauptabfragen 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 +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 schwächeren Clients in kurzer Zeit durchführbar. @@ -200,17 +200,17 @@ verwendet wird. Der größte Unterschied zur Standardimplementierung ist die Ver 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. -Zusammenfassend ist zu sagen, dass die \textit{Materialized View} eine gute Wahl sind, um die Listendarstellungen +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 Ressourcennutzung verringert wird. Zum anderen wird die Ressourcennutzung des Servers noch weiter reduziert, wenn die \textit{Json}"=Verarbeitung an den Client ausgelagert wird. -Durch die doppelte Datenhalten muss bei jeder Abfrage geprüft werden, ob der Nutzung der \textit{Materialized View} sinnvoll +Durch die doppelte Datenhaltung muss bei jeder Abfrage geprüft werden, ob die Nutzung der \textit{Materialized View} sinnvoll ist oder direkt auf denormalisierte Daten umgestellt werden sollte, weil der zusätzliche benötigte Speicher größer als 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 dadurch wird ein Zugriff auf so ein Objekt wieder -langsamer. Somit ist die Optimierung über die \textit{Materialized View} auf langezeit gesehen kostengünstiger und +und wirft alte Objekte aus dem Cache. Wenn dieser voll ist und 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. \section{Optimierung der Abfrage} @@ -219,7 +219,7 @@ stabiler. 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 gelöst werden. Bei größeren Abfragen mit mehreren Joins kann durch geschicktes umstellen die Performance verbessert -werden. Die Hauptabfrage der Dokumentenliste ist eine mit mehreren Joins, und diese wurde explizit untersucht. +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 @@ -233,9 +233,9 @@ Zeilenanzahl während der Verarbeitung enorm verringert werden, wodurch einige d umgestellt wurden. Durch die Umstellung konnte die Abfragezeit um mehr als das dreifache reduziert wurde. 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 +mehrere Tabellen besteht. Das Wichtigste hierbei ist, dass die Bedingungen und die Sortierkriterien auf der Haupttabelle arbeiten. Wenn dem nicht so ist, müssen Joins in die \textit{Common Table Expression} mit aufgenommen werden und damit funktioniert die Reduzierung der Datensätze nicht mehr. Bei der Selektion einer Tabelle hat diese Art -der Optimierung keine Auswirkung, hier hilft nur das geschickte setzen von Indexen auf die Tabelle, welche die +der Optimierung keine Auswirkung, hier hilft nur das geschickte Setzen von Indexen auf die Tabelle, welche die Bedingungen und die Sortierkriterien beinhalten. Dies wurde mit der Untersuchung der Abfrage auf die \textit{Materialized View} bestätigt. diff --git a/chapters/thesis/chapter07.tex b/chapters/thesis/chapter07.tex index 05e9104..39e70ac 100644 --- a/chapters/thesis/chapter07.tex +++ b/chapters/thesis/chapter07.tex @@ -10,18 +10,18 @@ % In der Gegenwart schreiben, außer bei verweisen auf die Arbeit, dann in der Vergangenheit! Die Untersuchungen am Beispiel des Wedekind"=Projektes zeigen, dass mehrere Optimierungsmöglichkeiten in den -Briefedition existieren. Für die Untersuchung wurde sich auf die Dokumentenliste beschränkt und anhand dieser +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 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 +%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. -Die Methode der Nutzerumfrage wurde nicht weiterverfolgt, da diese aufgrund zu wenigen Bedienern nicht zielführend war. +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 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. @@ -34,7 +34,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 messbar. Ab dem Zeitpunkt, dass Objekte aus dem Cache entfernt werden müssen, +speichern, sind die Verbesserung 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 @@ -51,13 +51,13 @@ durch die Umstellung der Ermittlung der unterlagerten Daten durch Hints eine Opt bezweckt das die unterlagerten Daten nicht einzeln für jede Zeile ermittelt wurde, 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 +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 -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. +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 visuell Darstellung +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 @@ -72,11 +72,11 @@ des Servers. \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 -Server durchführbar. Auf diese Weise könnten zusätzlich die Ressourcen am Server reduziert werden, beziehungsweise mit +Möglichkeiten für eine Optimierungen zu lassen. 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önne durch Umstellung der Abfragen und der Optimierung des ORM"=Mappers umgesetzt +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. diff --git a/expose.pdf b/expose.pdf index fef4681..bc0b998 100644 Binary files a/expose.pdf and b/expose.pdf differ diff --git a/marco-galster-config.tex b/marco-galster-config.tex index 23d6a7a..5b84c9d 100644 --- a/marco-galster-config.tex +++ b/marco-galster-config.tex @@ -25,7 +25,7 @@ \newcommand{\myUni}{FernUniversit\"at in Hagen\xspace} \newcommand{\mySubjectArea}{Lehrgebiet Datenbanken und Informationssysteme\xspace} \newcommand{\myLocation}{Höchstadt\xspace} -\newcommand{\myTime}{21. August 2024\xspace} +\newcommand{\myTime}{29. September 2024\xspace} \newcommand{\myVersion}{version 1.0\xspace} % **************************************************************************************************** @@ -61,3 +61,8 @@ % \definecolor{Black}{cmyk}{0, 0, 0, 0} \definecolor{Black}{HTML}{221E1F} % Definition von https://en.wikibooks.org/wiki/LaTeX/Colors \definecolor{Green}{HTML}{00A64f} + +% Farbiges Markieren mit \texthl{...} +\usepackage{soul} +% ToDos erstellen mit \todo{...} +\usepackage{todonotes} diff --git a/thesis-beamer.tex b/thesis-beamer.tex index 9fdae77..5a2e956 100644 --- a/thesis-beamer.tex +++ b/thesis-beamer.tex @@ -75,7 +75,7 @@ lineArrow/.style={arrows={-Latex[length=5pt 3 0]}}, every fit/.style={inner sep=.4em,draw} ] - \node (browser) [block] {WebBrowser}; + \node (browser) [block] {Webbrowser}; \node (fitClient) [rounded corners,fit=(browser)] {}; \node [left] at (fitClient.west) {Client}; diff --git a/thesis.pdf b/thesis.pdf index ddcb6d4..ec15205 100644 Binary files a/thesis.pdf and b/thesis.pdf differ