diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a8802d..22e74fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,21 +2,27 @@ "cSpell.language": "de-de,en", "cSpell.words": [ "autovacuum", + "Denormalisierung", "editionswissenschaftlich", "EFFW", + "Entitätsklassen", "Fouine", "freigeschalten", "Galster", "Glassfish", "JPQL", "Konsolenanwendungen", + "lesbarere", "Multifunktionalität", + "parsen", "Persistenzkontext", "Planerstatistiken", "Plantypen", "SFSB", + "tabellenähnlichen", "unterlagerte", - "Wallstein", + "vorverdichteten", + "Wallstein" ], "cSpell.ignoreRegExpList": [], "cSpell.overrides": [ @@ -31,6 +37,7 @@ "Classname", "Datasource", "Frontmatter", + "IntelliJ", "JNDI", "Laravel", "Latexmk", @@ -39,25 +46,71 @@ "Payara", "Poolname", "Postgresql", + "Redhat", "Ressources", + "Servlet", "Symfony", + "addresseeperson", + "adressee", + "ajax", "american", "asadmin", + "authorperson", + "birthstartday", + "birthstartmonth", + "birthstartyear", "classicthesis", + "createdat", + "datetype", + "dcap", + "deathstartday", + "deathstartmonth", + "deathstartyear", + "documentaddresseeperson", + "documentcategory", + "documentcoauthorperson", + "documentfacsimile", + "documentid", "downto", + "enddatestatus", + "endday", + "endmonth", + "endyear", "ferniunithesis", + "firstname", "fmtutil", "gpasswd", + "hcap", + "historicalperson", + "ispublishedindb", "javax", "jdbc", + "jsonlog", "maxint", + "modifiedat", "ngerman", + "openjpa", "pacman", "payara", "payra", + "perfstat", + "personid", "postgresql", "println", + "searchdocument", + "searchfulltext", + "searchreference", + "servlet", + "servlets", + "sitecity", + "startdate", + "startdatestatus", + "startday", + "startmonth", + "startyear", "texlive", + "typeof", + "validuntil", "wedekind", "xsep" ], diff --git a/chapters/thesis/appendix04.tex b/chapters/thesis/appendix04.tex index ea5bbb5..4c33a91 100644 --- a/chapters/thesis/appendix04.tex +++ b/chapters/thesis/appendix04.tex @@ -9,12 +9,12 @@ \label{ap:calling_script} Um die Messungen etwas zu vereinfachen wurde ein Skript erstellt um die Aufrufe gesammelt durchzuführen. Um die -Messungen durchzuführen werden die Befehl, wie in \ref{lst:calling_script_exec} dargestellt aufgerufen. +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, -wie dargestellt, über die Statistik von Docker zu ermitteln. Nun wird überwacht, das die CPU-Auslastung auf ein -niedriges Level fällt, danach kann das Skript für die Messung gerufen werden. +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. \includecode[bash]{chapters/thesis/appendix04_calling_script.sh}{lst:calling_script}{Calling Script} diff --git a/chapters/thesis/appendix05.tex b/chapters/thesis/appendix05.tex index 9d590fe..ec63741 100644 --- a/chapters/thesis/appendix05.tex +++ b/chapters/thesis/appendix05.tex @@ -8,9 +8,10 @@ \chapter{JSF Performance Statistics Servlet} \label{ap:jsf_performance_statistics_servlet} -Um die Cache-Informationen über einen \ac{API}"=Aufruf bereitzustellen, wird ein Servlet \ref{lst:servlet} und ein -Provider \ref{lst:servlet_provider} benötigt. Für die Aufnahme in der Routing, wird noch ein zusätzlicher Eintrag in -der \textit{web.xml} benötigt \ref{lst:servlet_activate}. +Um die Cache-Informationen über einen \ac{API}"=Aufruf bereitzustellen, wird ein Servlet (\autoref{lst:servlet}) und ein +Provider (\autoref{lst:servlet_provider}) benötigt. Um das Servlet abfragen zu können, muss es in das Routing +aufgenommen werden, hierfür wird noch ein zusätzlicher Eintrag in der \textit{web.xml} benötigt, der in +\autoref{lst:servlet_activate} dargestellt ist. \includecode[java]{chapters/thesis/appendix05_servlet.java}{lst:servlet}{Performance Statistics Servlet} diff --git a/chapters/thesis/chapter02.tex b/chapters/thesis/chapter02.tex index 4732ba3..d35636d 100644 --- a/chapters/thesis/chapter02.tex +++ b/chapters/thesis/chapter02.tex @@ -29,9 +29,7 @@ sind die \textit{Memory Buffers} notwendig um den Zugriff auf die Festplatte zu zu verringern. Um Anfragen die den Zugriff auf die Festplatte benötigen effizienter zu gestalten, bereiten die \textit{Services} die Datenstrukturen auf. -\mytodos{Grafik anders positionieren} - -\begin{figure}[h] +\begin{figure}[!ht] \begin{tikzpicture}[node distance=5em, block/.style={rectangle, rounded corners,minimum width=3cm,minimum height=1cm,text centered, draw=black,fill=green!30}, lineArrow/.style={arrows={-Latex[length=5pt 3 0]}}, diff --git a/chapters/thesis/chapter03.tex b/chapters/thesis/chapter03.tex index b953696..12c1034 100644 --- a/chapters/thesis/chapter03.tex +++ b/chapters/thesis/chapter03.tex @@ -126,10 +126,10 @@ Die Abfragen werden ebenfalls untersucht und mit verschiedenen Methoden optimier SQL"=Anfragen umgestellt und die Ausführungszeiten überprüft. Ebenfalls werden die Abfragen durch Criteria API erzeugt und dessen Ausführungszeit ermittelt. -Zusätzlich werden im SQL-Server Optimierungen vorgenommen, darunter zählen die materialized views, welche eine erweiterte -View 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 der -Performance und der Abfragedauern verkürzen können. +Zusätzlich werden im SQL-Server Optimierungen vorgenommen, darunter zählen die Materialisierten Sichten, 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 +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. diff --git a/chapters/thesis/chapter04.tex b/chapters/thesis/chapter04.tex index 9f212f8..64cb512 100644 --- a/chapters/thesis/chapter04.tex +++ b/chapters/thesis/chapter04.tex @@ -3,22 +3,17 @@ \chapter{Performance-Untersuchung} \label{ch:performance-checking} -\section{Auswertung des Systems} -\label{sec:performance-checking:system} +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 +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. -\mytodos{Hier die Auswertung des Produktionsservers unterbringen} +\section{Überprüfung des Servers} +\label{sec:performance-checking:server-checking} -\section{Statistiken im PostgreSQL auswerten} -\label{sec:performance-checking:postgresql-statistics} - -\mytodos{Logs auswerten, am besten vom Produktionsserver. Ebenfalls sollte man die Webseite -prüfen, die den Cache von OpenJPE auswerten} - -\section{Überprüfung des PostgreSQL und Servers} -\label{sec:performance-checking:postgresql-checking} - -Die einfachste Art die Einstellungen zu prüfen ist, die Abfrage in \ref{lst:postgresql-select-settings} am -Datenbankserver auszuführen. +Die einfachste Art die Einstellungen am PostgreSQL"=Server zu überprüfen, ist die Abfrage von +\ref{lst:postgresql-select-settings} am Datenbankserver auszuführen. \begin{lstlisting}[language=SQL,caption={Ermitteln der PostgreSQL Einstellungen},label=lst:postgresql-select-settings] SELECT name AS setting_name @@ -31,10 +26,16 @@ WHERE name IN ( , 'work_mem' , 'max_connections' , 'maintenance_work_mem' + , 'autovacuum' ) \end{lstlisting} -\mytodos{Konfiguration vom Produktionsserver prüfen} +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 +möglich, da kein Zugang zum aktuellen Produktionsservers möglich ist. \section{Einbau und Aktivieren von Performance-Messung} \label{sec:performance-checking:performance-measure} @@ -49,7 +50,7 @@ ausgewertet werden. Zusätzlich wird noch eine Implementierung der zugehörigen Factory"=Klasse \textbf{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 -\ref{lst:activate-factory} gezeigt wird, damit die Factory durch das System aufgerufen wird. +\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] @@ -59,11 +60,11 @@ eingehängt. Diese Implementierung wird dann noch in der \textbf{faces-config.xm \end{lstlisting} -Der Quellcode der Klassen ist im Anhang \ref{ap:jsf_performance_measure} zu finden. +Der Quellcode der Klassen ist im \autoref{ap:jsf_performance_measure} zu finden. Um die Abfragen im \textit{PostgreSQL} untersuchen zu können, ist es am leichtesten, wenn man die Konfiguration so -anpasst, dass alle Abfragen mit entsprechenden Zeitmessungen in die Log"=Datei des ausgegeben werden. -Zuerst werden über die Einstellungen unter \ref{lst:postgresql_logfile} die Datei und das Format definiert. +anpasst, dass alle Abfragen mit entsprechenden Zeitmessungen in die Log"=Datei ausgegeben werden. +Über die Einstellungen in \autoref{lst:postgresql_logfile} wird die Datei und das Format der Ausgabe definiert. \begin{lstlisting}[language=yaml,caption={PostgreSQL Dateikonfiguration},label=lst:postgresql_logfile] log_destination = 'jsonlog' @@ -74,7 +75,7 @@ log_file_mode = 0640 log_rotation_size = 100MB \end{lstlisting} -Über die Konfiguration unter \ref{lst:postgresql_logconf} wird definiert welche Werte mit protokolliert werden. Die +Ü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 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. @@ -97,3 +98,54 @@ log_statement = 'none' log_temp_files = 0 log_timezone = 'Europe/Berlin' \end{lstlisting} + +\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, +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 +ist in \autoref{lst:explain-easy} dargestellt. + +\begin{lstlisting}[language=SQL,caption={Aufruf von EXPLAIN},label=lst:explain-easy] +EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SUMMARY) + select * from document; +\end{lstlisting} + +\mytodos{hier noch die Typen der Knoten erklären?} + +Eine weitere Optimierungsmöglichkeiten sind 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 +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 Materialisierten +Sichten. 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. + +\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 +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 +weitere gesammelt und für die Erstellung der Abfragepläne verwendet \citep{PostgreS39:online}. + +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. diff --git a/chapters/thesis/chapter05.tex b/chapters/thesis/chapter05.tex index 5b478ff..94d9f6b 100644 --- a/chapters/thesis/chapter05.tex +++ b/chapters/thesis/chapter05.tex @@ -23,13 +23,13 @@ circa 60 Aufrufe des Scripts benötigt, damit der Server nicht mehr reagiert. Hi 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 Arbeitsspeicher -das Problem nicht löst, sondern nur verschiebt. +Mit der Konfiguration \texttt{-Xmx} wird der maximal verwendbare Heap"=Speicher in der \ac{JVM} definiert. +Dies zeigt direkt, dass es ein Problem in der Freigabe der Objekte gibt, da dass erhöhen des verwendbaren +Arbeitsspeicher das Problem nicht löst, sondern nur verschiebt. -Für alle nachfolgenden Messungen wird das Skript \ref{ap:calling_script} verwendet, welches die einzelnen Aufrufe -steuert. Die Ergebnisse werden in eine Tabelle überführt, wie in der Tabelle \ref{tbl:measure-without-cache}. -Hierbei werden die Aufrufzeiten der Webseite aus dem Skript für die Zeitmessung mit Mindest"=, Durchschnitt"= und +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}. +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 vom \textit{Glassfish}"=Server vor und nach dem Aufruf ermittelt und die Differenz gebildet, hierbei sollte im besten @@ -38,20 +38,17 @@ der \ac{JSF} ermittelt und die durchschnittlichen Zeiten mit in der Tabelle darg 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 -Änderung am Code vorgenommen wurde. Das Ergebnis dieser Messung ist in \ref{tbl:measure-without-cache} zu finden. Diese -zeigen auch direkt ein erwartetes Ergebnis, dass der erste Aufruf bedeutend länger dauert als die Nachfolgenden. +Ä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. 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 gehalten werden sollten. -\mytodos{Diese Tabelle vielleicht auch einfach komplett streichen, da der Datenbestand anders ist, und das wichtigste -die Zeit der SQL-Abfragen nicht sichtbar ist} - -\begin{table}[h!] +\begin{table}[!h] \centering \begin{tabular}{|r|r|r|r|r|r|r|r|} \hline - & \multicolumn{3}{c}{Aufrufzeit (ms)} & & \multicolumn{3}{|c|}{RSS (MB)} \\ + & \multicolumn{3}{c|}{Aufrufzeit (ms)} & & \multicolumn{3}{c|}{RSS (MB)} \\ \hline \# & min & avg & max & Queries & davor & danach & diff \\ \hline @@ -68,14 +65,14 @@ die Zeit der SQL-Abfragen nicht sichtbar ist} Vor jedem weiteren Test-Lauf wurde 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 Materialisierten Sichten -\textbf{searchreference} und \textit{searchfulltext} erklärbar. Zusätzlich ist noch ein zyklischer Dienst +\textit{searchreference} und \textit{searchfulltext} erklärbar. Zusätzlich ist noch ein zyklischer Dienst \textit{SearchEntityService} vorhanden, der zum Start und alle sechs Stunden den Datenbestand für die Suche aufbereitet und entsprechend einige Abfragen an die Datenbank absetzt. Da weder die Sichten noch der Dienst für die Dokumentenliste 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 Anhang -\ref{ap:docker_config} beschrieben. +PostgreSQL und den Payara-Server ein Docker-Container erzeugt und diese limitiert. Die Konfiguration ist im +\autoref{ap:docker_config} beschrieben. Mit dem neuen Aufbau ergeben sich nun neue Messungen. 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 @@ -121,9 +118,8 @@ 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. Oder man muss die Duplikate auf der Serverseite -zusammenführen. -\mytodos{Gefällt der Verena nicht so} +Dadurch würden sich die Anzahl der Dokumentenliste erhöhen. Eine weitere Möglichkeit wäre es, die Duplikate auf der +Serverseite zusammenzuführen. \section{Caching im OpenJPA} \label{sec:performance-investigation-application:caching-openjpa} @@ -137,16 +133,16 @@ angeheftete Objekte nicht beachtet. Die Anzahl der Soft References kann ebenfalls über eine Einstellung gesteuert werden. Hierfür wird die Anzahl der Elemente über \textit{SoftReferenceSize} gesetzt, dessen Wert im Standard auf \textit{unbegrenzt} steht. Mit dem Wert -\textit{0} werden die Soft Referencen komplett deaktiviert. Über die Attribute an den Entitätsklassen, können diese +\textit{0} werden die Soft Referenzen komplett deaktiviert. Über die Attribute an den Entitätsklassen, können diese Referenzen ebenfalls gesteuert werden, hierzu muss eine Überwachungszeit angegeben werden. Diese Zeit gibt in ms an, wie lange ein Objekt gültig bleibt. Mit dem Wert \textit{-1} wird das Objekt nie ungültig, was ebenfalls der Standardwert ist. -Zuerst wird mit aktivierten Cache mit einer Cache-Größe von 1000 Elemente getestet. Wie in \ref{tbl:measure-ojpa-active} -zu sehen, dauert auch hier der erste Aufruf minimal länger als ohne aktiviertem Cache. Alle Nachfolgenden Aufrufe -wiederrum sind um 100ms schneller in der Verarbeitung. Auch bei der Anzahl der Anfragen an die Datenbank kann der -Rückgang der Anfragen sehr gut gesehen werden. Aktuell kann die Verringerung des wachsenden Speicherbedarfs nur nicht -erklärt werden. +Zuerst wird mit aktivierten Cache mit einer Cache-Größe von 1000 Elemente getestet. Wie in +\autoref{tbl:measure-ojpa-active} zu sehen, dauert auch hier der erste Aufruf minimal länger als ohne aktiviertem +Cache. Alle Nachfolgenden Aufrufe wiederrum sind um 100ms schneller in der Verarbeitung. Auch bei der Anzahl der +Anfragen an die Datenbank kann der Rückgang der Anfragen sehr gut gesehen werden. Aktuell kann die Verringerung des +wachsenden Speicherbedarfs nur nicht erklärt werden. \begin{table}[h!] \centering @@ -170,12 +166,12 @@ erklärt werden. \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 -\ref{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 um 100 ms -beschleunigt werden konnte. +\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 +um 100 ms beschleunigt werden konnte. -\begin{table}[h!] +\begin{table}[!ht] \centering \resizebox{\textwidth}{!}{ \begin{tabular}{|r|r|r|r|r|r|r|r|r|r|r|r|r|r|r|} @@ -196,9 +192,9 @@ beschleunigt werden konnte. \label{tbl:measure-ojpa-active-bigger} \end{table} -Bei dem deaktivieren der \textit{SoftReference} und dem kleineren Cache zeigt sich keine große Differenz. Somit scheint -die \textit{SoftReference} nicht das Problem für den steigenden Arbeitsspeicher zu sein, wie in Tabelle -\ref{tbl:measure-ojpa-active-bigger-no-softref} zu sehen. +Bei dem deaktivieren der \textit{SoftReference} und dem kleineren Cache zeigt sich keine große Differenz, somit scheint +die \textit{SoftReference} nicht das Problem für den steigenden Arbeitsspeicher zu sein, wie in +\autoref{tbl:measure-ojpa-active-bigger-no-softref} ersichtlich. % document, documentaddresseeperson, first/last, documentcoauthorperson, count und documentfacsimile \begin{table}[h!] @@ -229,11 +225,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 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 \ref{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. +Ü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. % document, documentaddresseeperson, first/last, documentcoauthorperson, count und documentfacsimile \begin{table}[h!] @@ -257,6 +253,8 @@ abfragt. \label{tbl:measure-cached-queries} \end{table} +\mytodos{Queryzeiten fehlen nocht} + \section{Caching im JPA} \label{sec:performance-investigation-application:caching-jpa} @@ -305,6 +303,7 @@ abfragt. \label{sec:performance-investigation-application:caching-ejb} Die Cache-Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Servers zu erreichen. Hier + \mytodos{Cache config noch definieren} \begin{table}[h!] @@ -331,8 +330,8 @@ Die Cache-Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Se \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 \ref{lst:jpql-document-list-jpql} verwendet. Die Namen mit vorangestellten Doppelpunkt -sind Übergabevariablen. +Dokumentenliste wird der Code aus dem \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] SELECT DISTINCT d FROM Document d @@ -344,9 +343,9 @@ AND d.isPublishedInDb = :published ORDER BY d.documentId ASC \end{lstlisting} -In dem dazugehörigen Code am Server wird der JPQL-Code als NamedQuery hinterlegt und über den Name \textit{Document.findAll} -referenziert. Eine Veränderung der Abfrage ist hier leider nicht möglich, wie man im Code \ref{lst:jpql-document-list} -sehen kann. +In dem dazugehörigen Code am Server wird der JPQL-Code als NamedQuery hinterlegt und über den Name +\textit{Document.""findAll} referenziert. Eine Veränderung der Abfrage ist hier leider nicht möglich, wie man im Code +aus \autoref{lst:jpql-document-list} sehen kann. \begin{lstlisting}[language=Java,caption={Java JPQL Dokumentenliste},label=lst:jpql-document-list] List myResultList = createNamedTypedQuery("Document.findAll") @@ -364,41 +363,40 @@ if(myResultList != null && !myResultList.isEmpty()) { \end{lstlisting} Da dieser Code direkt so aus dem Projekt kommt, wird hierfür keine gesonderte Zeitmessung durchgeführt, da diese der -Messung \ref{tbl:measure-without-cache} entspricht. +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 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. +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 +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 \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 mit Vorsicht zu verwenden. -Mit dem Hint \textit{openjpa.FetchPlan.EagerFetchMode} wird definiert, wie zusammengehörige Objekte abgefragt werden. +Mit dem Hint \textit{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 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 CoAuthoren durchgeführt werden, sondern es wird nur eine Abfrage abgesetzt für +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 Konfiguraiton für Unterklassen definiert. Die -Möglichkeiten entsprechen der vom \textit{openjpa.FetchPlan.EagerFetchMode}. +Mit dem Hint \textit{openjpa.""FetchPlan.""SubclassFetchMode} ist die Konfiguration für Unterklassen definiert. Die +Möglichkeiten entsprechen der vom \textit{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 Objekte -mitgeladen werden. Damit wird zwar die Abfrage beschleunigt, aber nur aufgrund fehlender Datenbestände. -\mytodos{besser formulieren} +Der letzte Hint \textit{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} @@ -406,7 +404,7 @@ mitgeladen werden. Damit wird zwar die Abfrage beschleunigt, aber nur aufgrund f 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 -versorgt werden, wie es in \ref{lst:criteria-api} gezeigt wird. +versorgt werden, wie es in \autoref{lst:criteria-api} gezeigt wird. \begin{lstlisting}[language=Java,caption={Criteria API Dokumentenliste},label=lst:criteria-api] CriteriaBuilder cb = getEntityManager().getCriteriaBuilder(); @@ -434,9 +432,9 @@ if (myResultList != null && !myResultList.isEmpty()) { } \end{lstlisting} -Wie in der Messung \ref{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 Abfragen -in den Java-Objekten fast identisch sind. Und in der Datenbank sind die Anfragen identisch zu denen über JPQL. +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 +Abfragen in den Java-Objekten fast identisch sind. Und in der Datenbank sind die Anfragen identisch zu denen über JPQL. \begin{table}[h!] \centering @@ -463,11 +461,17 @@ 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 \textit{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} +\section{Optimierung der Abfrage} +\label{sec:performance-investigation-application:optimizing-query} + +Für die Optimierung der Abfrage wird zuerst die Hauptabfrage ermittelt, die auch in \autoref{lst:documentlist} zu +sehen ist. + +\section{Materialized Views} \label{sec:performance-investigation-application:materialized-views} Materialized Views sind Sichten in der Datenbank, die beim erstellen der Sicht den aktuellen Zustand ermitteln und @@ -477,16 +481,16 @@ Sichten auch Indexe erstellt werden, um noch effektiver die Abfragen bearbeiten 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 igoriert ewrden. +die Abfrage der Daten ist, und nicht das editieren, kann dieser Nachteil bei entsprechender Optimierung ignoriert werden. In diesem Test, wurde zusätzlich zur normalen Abfragen noch die nachfolgenden einzelabfragen als Sub-Selects -hinzugefügt, wie in \ref{lst:sql-materialized-view} zu sehen. Somit können die nachfolgenden einzelnen Abfragen +hinzugefügt, wie in \autoref{lst:sql-materialized-view} zu sehen. Somit können die nachfolgenden einzelnen Abfragen eingespart werden. Dies wiederrum geht aber auf die Performance der Erstellung der Sicht und ihrer Aktualisierung. \begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view] CREATE MATERIALIZED VIEW searchdocument AS SELECT - d.id, d.documentId, d.datetype, d.startdatestatus, d.startyear, + d.id, d.documentid, d.datetype, d.startdatestatus, d.startyear, d.startmonth, d.startday, d.enddatestatus, d.endyear, d.endmonth, d.endday, ( @@ -565,7 +569,7 @@ LEFT JOIN sitecity sc ON sc.id = d.city_id; \end{lstlisting} Zusätzlich werden noch einige Indexe hinzugefügt, für eine bessere Performance bei der Abfrage, wie in -\ref{lst:sql-materialized-view-index} zu sehen. +\autoref{lst:sql-materialized-view-index} zu sehen. \begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view-index] CREATE INDEX idx_searchdocument_documentid @@ -612,7 +616,7 @@ CREATE INDEX idx_searchdocument_documentcategory \label{tbl:measure-materialized-view} \end{table} -Wie in Tabelle \ref{tbl:measure-materialized-view} zu sehen, bringt die Verwendung der Materialized View ein Verbesserung +Wie in \autoref{tbl:measure-materialized-view} zu sehen, bringt die Verwendung der Materialized View ein 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 einzelabfragen für die Adressen der Personen @@ -620,15 +624,15 @@ 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 Sicht -mit integriert. Dies bedeutet eine Erweiterung der Sicht aus \ref{lst:sql-materialized-view} um -\ref{lst:sql-materialized-view-ext} und das entfernen der Parameter aus dem SQL-Anfragen im Java-Code. +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. \begin{lstlisting}[language=SQL,caption={SQL Materialized View Erweiterung},label=lst:sql-materialized-view-ext] WHERE d.validuntil > NOW() AND d.ispublishedindb = true; \end{lstlisting} -Nach dem Anpassungen haben sich dann die Werte aus \ref{tbl:measure-materialized-view-ext} ergeben. +Nach dem Anpassungen haben sich dann die Werte aus \autoref{tbl:measure-materialized-view-ext} ergeben. \begin{table}[h!] \centering @@ -661,21 +665,21 @@ erzeugt, noch ohne eine Konvertierung der ermittelten Daten in das Objekt, steig 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 kostet die meiste Zeit. -Bei der Verwendung des Hints \textit{openjpa.FetchPlan.FetchBatchSize} kann die Abfrage enorm verschlechtern. Wenn +Bei der Verwendung des Hints \textit{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. -Das aktivieren der Cache-Optionen wie in \ref{sec:performance-investigation-application:caching-openjpa} oder in -\ref{sec:performance-investigation-application:caching-query} dargestellt, haben keine Auswirkung auf die Performance. +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. -Nun wird noch geprüft, welche Performance das parsen der Json-Informationen im Server benötigt. Im ersten Schritt wird +Nun wird noch geprüft, welche Performance das parsen der Json"=Informationen im Server benötigt. Im ersten Schritt wird die Parse-Funktion auskommentiert und die Seite nochmal 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 -\ac{Json}"=Daten benötigt. Hierfür werden die Daten in einem versteckten \textbf{span}"=Element hinterlegt, wie es im -Beispiel \ref{lst:jsf-datatable-json} zu sehen ist. Die hinterlegte \ac{CSS}"=Klasse ist zum auffinden der Elemente +\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. 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 neu übertragenen Elemente in eine lesbare Form gebracht werden. @@ -692,11 +696,11 @@ für den späteren Javascript. Das \textbf{ajax}"=Element im Beispiel ist notwen \end{lstlisting} -Um nun die übertragenen \ac{Json}"=Daten in eine darstellbare Form zu bringen, benötigt man noch eine -JavaScript"=Funktion. Diese Funktion \ref{lst:jsf-datatable-json-convert} wird ermittelt erst alle versteckten Elemente, -parsed den Inhalt und erstellt neue \ac{HTML}"=Elemente mit dem darzustellenden Inhalt. Zusätzlich wird noch eine -Zeitmessung mit 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 gerufen. +Um nun die übertragenen \textit{Json}"=Daten in eine darstellbare Form zu bringen, benötigt man noch eine +JavaScript"=Funktion. Die Funktion aus \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 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] function isEmpty(str) { @@ -744,32 +748,4 @@ durchgeführt werden. Daher werden nun die Laufzeiten am Server und am Client zu 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. -%\mytodos{hier noch darauf eingehen, dass die Hauptarbeit nicht beim editieren sondern bei der Anzeige ist} -\mytodos{Hier könnte man auch den Query-Cache nochmal verwenden, da die anfragen nun fix wären} \mytodos{Grundlagen zur Materialized-View noch hinterlegen} - -\section{Statische Webseiten} -\label{sec:performance-investigation-application:static-website} - -Wenn man die Dokumentenliste als statische Webseiten ablegt, werden die Zugriffszeiten sehr kurz sein. Darüber hinaus -funktionieren in statische Webseiten aber keine Suche oder eine Sortierung. Die Sortierung könnte durch das erstellen -von statischen Seite 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. - -Die Umstellung der Suche auf Client!=Basis wäre noch eine Möglichkeit, dafür benötigen die Clients entsprechend -Leistung und es muss eine Referenzdatei erstellt werden, die alle Informationen über die Dokumente beinhaltet, nach der -gesucht werden kann. - -Daher ist eine Umstellung auf statische Webseiten nicht sinnvoll. - -\section{Client basierte Webseiten} -\label{sec:performance-investigation-application:client-side-rendering} - -Als weitere Möglichkeit könnte man die Webseite so umbauen, dass die Daten erst im Nachgang über eine AJAX-Anfrage -ermittelt und die Sortierung und Aufteilung im Client durchgeführt wird. Hierbei wird aber je nach Datenmenge ein -großer Speicher am Client benötigt und die Rechenleistung wird auf den Client verschoben. - -Dies wiederrum ist ein Vorteil für den Serverbetreiber, da durch die Verschiebung weniger Rechenleistung am Server -benötigt wird. Gleichzeitig würde man damit wiederrum schwächere Clients, wie Smartphones, aussperren, da bei diesem -die notwendige Rechenleistung fehlt, um die Webseite in annehmbarer Zeit darzustellen. diff --git a/chapters/thesis/chapter06.tex b/chapters/thesis/chapter06.tex index 1455655..dc78698 100644 --- a/chapters/thesis/chapter06.tex +++ b/chapters/thesis/chapter06.tex @@ -7,9 +7,18 @@ Nun werden die durchgeführten Anpassungen anhand ihre Effektivität betrachtet diese eine Optimierung darstellen. Weiterhin werden die Nachteile der Anpassungen überprüft und und bei der Betrachtung der Effektivität mit beachtet. +Es wurden die Konfigurationen der Caches von OpenJPA, JPA und EJB aktiviert und deren Auswirkung betrachtet. Bei den +Caches, bei denen eine Größe angebbar ist, wurde zusätzlich mit der Anzahl variiert, um zu ermitteln in welchen Umfang +sich diese auswirkt. Des Weiteren wird die Art der Programmierung für die Abfragen betrachtet, ob es signifikante +Unterschiede in der Performance und der Abarbeitung ergibt. Als weitere Punkt werden die Abfragen an die Datenbank +untersucht, um zu ermitteln ob diese durch Umstellung verbessert werden können. Als letzten werden die Materialisierten +Sichten verwendet, um zu ermitteln, ob durch einen vorverdichteten und aufbereiteten Datenbestand die Abfragen +beschleunigt werden können. + \mytodos{Zusätzlich beschreiben welche Möglichkeiten man genau genutzt hat und warum bzw. warum nicht} \section{Nutzerumfrage} +\label{sec:evaluation:user-survey} Zusätzlich war noch eine Befragung unter den Benutzer und den Entwicklern geplant. Da hierfür nur fünf Personen zur Verfügung stehen, ist dies nicht zielführend. Daher ist die sinnvolle Alternative ein rein technischer Ansatz, der @@ -18,15 +27,13 @@ gewählt wurde. \section{Statische Webseiten} \label{sec:evaluation:static-website} -\mytodos{prüfen wohin damit, hier oder odch in 5 lassen} - Wenn man die Dokumentenliste als statische Webseiten ablegt, werden die Zugriffszeiten sehr kurz sein. Darüber hinaus funktionieren in statische Webseiten aber keine Suche oder eine Sortierung. Die Sortierung könnte durch das erstellen von statischen Seite 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. -Die Umstellung der Suche auf Client!=Basis wäre noch eine Möglichkeit, dafür benötigen die Clients entsprechend +Die Umstellung der Suche auf Client"=Basis wäre noch eine Möglichkeit, dafür benötigen die Clients entsprechend Leistung und es muss eine Referenzdatei erstellt werden, die alle Informationen über die Dokumente beinhaltet, nach der gesucht werden kann. @@ -35,8 +42,6 @@ Daher ist eine Umstellung auf statische Webseiten nicht sinnvoll. \section{Client basierte Webseiten} \label{sec:evaluation:client-side-rendering} -\mytodos{prüfen wohin damit, hier oder odch in 5 lassen} - Als weitere Möglichkeit könnte man die Webseite so umbauen, dass die Daten erst im Nachgang über eine AJAX-Anfrage ermittelt und die Sortierung und Aufteilung im Client durchgeführt wird. Hierbei wird aber je nach Datenmenge ein großer Speicher am Client benötigt und die Rechenleistung wird auf den Client verschoben. @@ -45,11 +50,11 @@ Dies wiederrum ist ein Vorteil für den Serverbetreiber, da durch die Verschiebu benötigt wird. Gleichzeitig würde man damit wiederrum schwächere Clients, wie Smartphones, aussperren, da bei diesem die notwendige Rechenleistung fehlt, um die Webseite in annehmbarer Zeit darzustellen. -\section{Statistiken im PostgreSQL auswerten} - -\section{Vergleich der Ergebnisse vor und nach der Optimierung} +\section{Auswertung der Ergebnisse vor und nach der Optimierung} +\label{sec:evaluation:result-optimization} \subsection{Caching im OpenJPA} +\label{sec:evaluation:result-optimization:caching-jpa} Bei der Verwendung des OpenJPA"=Caches gibt es einige Verbesserungen in der Geschwindigkeit zu sehen. Die Höhe der Optimierungen hängt stark von der gewählten Cache"=Größe und der aufgerufenen Webseiten ab. Solange die Anfragen sich @@ -57,7 +62,7 @@ auf die gleichen Objekte beziehen und diese alle im Cache hinterlegt werden kön hoch aus. Sobald bei den Anfragen aber häufig die zu ermittelnden Objekt sich unterscheiden und alte Objekte wieder aus dem Cache entfernt werden, fällt die Performance"=Verbesserung immer geringer aus. -Das entfernen der Objekte kann zwar umgangen werden, indem die häufig abgefragten Objekte gepinnt werden, was aber +Das Entfernen der Objekte kann zwar umgangen werden, indem die häufig abgefragten Objekte gepinnt werden, was aber den Speicherbedarf noch weiter erhöht, da diese Objekte nicht in die Zählung der Cache"=Objekte beachtet werden. Was uns direkt zum größten Nachteil diese Caches kommen lässt, die notwendig Speichermenge die ständig zur Verfügung gestellt werden muss. Damit ist immer ein gewisser Grundbedarf notwendig, da sich der Speicher bis zum eingestellten @@ -67,7 +72,7 @@ zur Verfügung steht. Hierbei ist aber noch zu beachten, dass die Optimierung durch den Cache nicht die Laufzeit der Abfragen in der Datenbank enorm verringert hat, sondern die Laufzeit beim erstellen der Objekte im \textit{OpenJPA}"=Framework. Dies sieht man -sehr gut schon bei der ersten Messung, wie in \autoref{lst:measure-ojpa-active}. Hierbei werden die Laufzeit in der +sehr gut schon bei der ersten Messung, wie in \autoref{tbl:measure-ojpa-active}. Hierbei werden die Laufzeit in der Datenbank im Schnitt um circa 5 ms reduziert, aber die komplette Webseite wird fast 100 ms schneller an den Client ausgeliefert. Dies ist nur dadurch erklärbar, dass das erstellen und mit den Datenwerte zu befüllen mehr Zeit kostet, als das Objekt aus dem Cache zu ermitteln und zurückzugeben. @@ -77,6 +82,7 @@ wenn der Großteil der Objekte im Cache gehalten werden kann. Bei Bedarf sollten explizit im Cache aufgenommen und angepinnt werden. \subsection{Cached Queries} +\label{sec:evaluation:result-optimization:cached-queries} 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. Da in diesem Fall in der Tabelle @@ -90,8 +96,9 @@ Dadurch ist dieser Cache für eine Performance"=Verbesserung in unseren Fall nic \subsection{Caching in EJB} \subsection{Abfragen mit JPQL und Criteria API} +\label{sec:evaluation:result-optimization:jpal-capi} -Bei dem Vergleich zwischen den 2 Abfragemöglichkeiten der \ac{JPQ} und der Criteria API konnte in der Art der Abfragen +Bei dem Vergleich zwischen den 2 Abfragemöglichkeiten der \ac{JPQL} und der Criteria API konnte in der Art der Abfragen kein Unterschied dargestellt werden. Die Abfragen der beiden Systeme sind auf der Datenbankseite komplett identisch. Auch in der Übertragung der Daten aus der Datenbank in die Java"=Objekte konnte keine Unterschied in der Art und Geschwindigkeit festgestellt werden. @@ -112,9 +119,10 @@ Aufgrund dessen ist die Entscheidung der Technik für die Performance irrelevant jeweiligen Einsatzzweck besser beziehungsweise einfacher zu programmieren ist. Das setzen der richtigen Hints wiederrum ist in beiden Fällen äußerst wichtig. Explizit 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 Hit auf \textit{parallel} zu setzen. +ausgegangen werden kann. Gerade bei ein größeren Anzahl lohnt es sich den Hint auf \textit{parallel} zu setzen. Gleiches gilt den Hint SubclassFetchMode, dieser steuert die Abfragen im falle von abgeleitet Klassen. \subsection{Materialized View} +\label{sec.evaluation:result-optimization:materialized-view} \mytodos{hier weiter machen} \ No newline at end of file diff --git a/expose-ref.bib b/expose-ref.bib index 48be266..bf8f29d 100644 --- a/expose-ref.bib +++ b/expose-ref.bib @@ -63,6 +63,24 @@ urldate = {2024-09-12} }, +@online{PostgreS39:online, + author = {}, + title = {PostgreSQL: Documentation: 16: 54.27. pg\_stats}, + url = {https://www.postgresql.org/docs/current/view-pg-stats.html}, + month = {}, + year = {}, + urldate = {2024-09-14} +}, + +@online{PostgreS12:online, + author = {}, + title = {PostgreSQL: Documentation: 16: CREATE STATISTICS}, + url = {https://www.postgresql.org/docs/16/sql-createstatistics.html}, + month = {}, + year = {}, + urldate = {2024-09-14} +}, + @online{AspNetCore:2024:MVC, year = 2024, url = {https://learn.microsoft.com/de-de/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0}, diff --git a/thesis.pdf b/thesis.pdf index 9b36e5e..6b51e1e 100644 Binary files a/thesis.pdf and b/thesis.pdf differ diff --git a/thesis.tex b/thesis.tex index 0b785ef..c12c38a 100644 --- a/thesis.tex +++ b/thesis.tex @@ -44,7 +44,6 @@ %************************************************************************* \addbibresource{Expose-ref.bib} - %************************************************************************* % GO!GO!GO! MOVE IT! %************************************************************************* @@ -52,6 +51,12 @@ \frenchspacing \raggedbottom \selectlanguage{ngerman} % ngerman, american +%************************************************************************* +% Hyphenation - scheinbar erst nach Sprachselektion, sonst funktioniert es nicht +%************************************************************************* +\hyphenation{ + Spei-cher-be-darf +} %\renewcommand*{\bibname}{new name} %\setbibpreamble{} \pagenumbering{roman}