Daily CheckIn
This commit is contained in:
parent
e096c14dcc
commit
0d7fc1ae62
11 changed files with 272 additions and 161 deletions
55
.vscode/settings.json
vendored
55
.vscode/settings.json
vendored
|
@ -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"
|
||||
],
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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]}},
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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]
|
||||
<factory>
|
||||
|
@ -59,11 +60,11 @@ eingehängt. Diese Implementierung wird dann noch in der \textbf{faces-config.xm
|
|||
</factor>
|
||||
\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.
|
||||
|
|
|
@ -24,12 +24,12 @@ in der Log-Datei protokolliert und der Server verwendet nun circa 4700 MB RSS. B
|
|||
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.
|
||||
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<Document> 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
|
|||
</p:column>
|
||||
\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.
|
||||
|
|
|
@ -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}
|
|
@ -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},
|
||||
|
|
BIN
thesis.pdf
BIN
thesis.pdf
Binary file not shown.
|
@ -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}
|
||||
|
|
Loading…
Reference in a new issue