bachelor-thesis/chapters/thesis/chapter04.tex
2024-09-26 23:43:38 +02:00

159 lines
9.6 KiB
TeX

% !TeX root = ../../thesis.tex
\chapter{Performance-Untersuchung}
\label{ch:performance-checking}
Für die Untersuchung der Performance"=Probleme sollten einige Vorbereitungen getroffen werden. Dazu gehören die
Konfigurationen des Servers und in welcher Art und Umfang Anpassungen für die Performance"=Messungen an der Software
durchgeführt werden müssen. Hierbei ist zu beachten, dass die Anpassungen minimal sind, damit die Messung selbst nicht
das Ergebnis verfälscht. Zum Abschluss wird noch auf die Untersuchung der Abfragen eingegangen, wie diese im
PostgreSQL"=Server durchgeführt wird.
\section{Überprüfung des Servers}
\label{sec:performance-checking:server-checking}
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
, setting AS setting_value
, unit AS setting_unit
FROM pg_settings
WHERE name IN (
'shared_buffers'
, 'temp_buffers'
, 'work_mem'
, 'max_connections'
, 'maintenance_work_mem'
, 'autovacuum'
)
\end{lstlisting}
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 \texttt{VACUUM} und \texttt{ANALYZE} aktiv ist. Eine weitere Überprüfung des Servers ist nicht
möglich, da kein Zugang zum aktuellen Produktionsservers möglich ist.
\section{Einbau und Aktivieren von Performance-Messung}
\label{sec:performance-checking:performance-measure}
Um eine Messung der Performance in der Webseite durchführen zu können, gibt es in \ac{JSF} die Möglichkeit, über eine
eigene Implementierung der Klasse \texttt{ViewDeclarationLanguageWrapper} sich in das Generieren der Webseite
einzuhängen. Hierbei können die Funktionen für das Erstellen, das Bauen und das Rendern der Webseite überschrieben
werden. In den überschriebenen Funktionen werden nun Laufzeiten gemessen und die ermittelten Zeiten mit einer Kennung
in die Log"=Datei eingetragen. Durch die Kennung, können die Zeiten im Nachgang über ein Script ermittelt und
ausgewertet werden.
Zusätzlich wird noch eine Implementierung der zugehörigen Factory"=Klasse \texttt{ViewDeclarationLanguageFactory}
benötigt. Durch diese Factory"=Klasse wird der eigentlichen Wrapper mit der Performance-Messung in die Bearbeitungsschicht
eingehängt. Diese Implementierung wird dann noch in der \texttt{faces-config.xml} eingetragen, wie das in
\autoref{lst:activate-factory} gezeigt wird, damit die Factory durch das System aufgerufen wird.
\begin{lstlisting}[language=xml,caption={Einbindung Factory},label=lst:activate-factory]
<factory>
<view-declaration-language-factory>
de.wedekind.utils.VdlLoggerFactory
</view-declaration-language-factory>
</factor>
\end{lstlisting}
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 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'
logging_collector = on
log_directory = 'log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_file_mode = 0640
log_rotation_size = 100MB
\end{lstlisting}
Über die Konfiguration unter \autoref{lst:postgresql_logconf} wird definiert welche Werte protokolliert werden. Die
wichtigste Einstellung ist \texttt{log\_min\_duration\_statement}, diese definiert, ab welcher Laufzeit eine Abfrage
protokolliert werden soll. Mit dem Wert 0 werden alle Abfragen protokolliert. Alle weitere Einstellungen sind so
gesetzt, dass nicht unnötige Abfragen für die spätere Auswertung mit \textit{pgBadger} protokolliert werden.
Zusätzlich ist die Einstellung \texttt{log\_temp\_files} auf 0 zu setzen, dadurch werden alle erzeugten temporären
Dateien und ihre Größe ebenfalls protokolliert. Diese Dateien entstehen, wenn der temporäre Puffer für die Abfrage
nicht ausreicht und die Zwischenergebnisse ausgelagert werden müssen.
\begin{lstlisting}[language=yaml,caption={PostgreSQL Ausgabekonfiguration},label=lst:postgresql_logconf]
log_min_duration_statement = 0
log_autovacuum_min_duration = 10
log_checkpoints = off
log_connections = on
log_disconnections = on
log_disconnections = on
log_duration = off
log_error_verbosity = default
log_hostname = on
log_lock_waits = on
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 \texttt{EXPLAIN} ist im PostgreSQL vorhanden, um den Abfrageplan einer Abfrage zu ermitteln und
darzustellen, um diesen zu untersuchen. Der Abfrageplan ist als Baum dargestellt, bei welchem die Knoten die
unterschiedlichen Zugriffsarten darstellen. Die Verbindung der Knoten und der Aufbau zeigt die Operationen, wie
etwa Joins, Aggregierung und Sortierung, und die Reihenfolgen der Abarbeitung. Zusätzlich sind auch Zwischenschritte,
wie Zwischenspeicherungen ersichtlich. Zu jeder Operation gibt es neben dem Typ noch zusätzliche Informationen, wie
die geschätzten Anlauf"= und Gesamtkosten (\textit{costs}), die geschätzte Anzahl der Zeilen (\textit{rows}) und die
geschätzte Breite jeder Zeile (\textit{width}). Der Wert von \textit{costs} wird bei übergeordneten Knoten summiert.
Bei der Option \texttt{ANALYZE} wird die Abfrage ausgeführt und die echten Werte und Laufzeiten angezeigt. Ohne diese,
wird nur der Plan erstellt und dargestellt. Durch \texttt{VERBOSE} wird der Abfrageplan um zusätzliche Informationen
angereichert. Die Option \texttt{BUFFERS} erweitert die Informationen über die Nutzung der Caches. Für eine
Zusammenfassung am Ende des Abfrageplans, gibt es die Option \texttt{summary}. Eine vereinfachte Form des Aufrufs
ist in \autoref{lst:explain-easy} dargestellt.
\begin{lstlisting}[language=SQL,caption={Aufruf von EXPLAIN},label=lst:explain-easy]
EXPLAIN (ANALYZE, VERBOSE, BUFFERS, SUMMARY)
select * from document;
\end{lstlisting}
\todo{bei seq scan ... nochmal neu überlegen + Satz mit seigenden kosten fehlt}
Die zwei bekanntesten Knotentypen sind \texttt{Seq Scan} und \texttt{Index Scan}. \texthl{Wenn eine Tabelle Zeile für Zeile
gelesen wird,} zeigt der Abfrageplan einen \texttt{Seq Scan}"=Knoten an. Hierbei entsteht, unabhängig davon ob eine
Bedingung zum filtern vorhanden ist, eine unsortierte Liste dessen Startkosten entsprechend niedrig sind. Je weiter die
Liste durchlaufen wird, desto höher steigen die notwendigen Kosten. Die kostengünstigere Alternative ist der
\texttt{Index Scan}, bei dem der Index nach den Kriterien durchsucht wird, was meist durch den Aufbau des Index als
BTree (Multi"=Way Balanced Tree) rapide geht.
Eine weitere Optimierungsmöglichkeit ist die Verwendung von Indexe. Diese sind aber mit Bedacht zu wählen, da bei
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 aktualisiert werden. Ebenfalls ist die Reihenfolge der Spalte in einem
zusammengesetzten Index von Bedeutung. Als Grundlage sollte hier mit der Spalte gestartet werden, welche die größte
Einschränkung durchführt. Zusätzlich muss die Art des Index definiert werden, welche davon abhängig ist, mit welcher
Vergleichsoperation auf die Tabellenspalte zugegriffen wird.
Um größere und aufwendigere Abfragen zu optimieren, bietet der PostgreSQL noch die Möglichkeit von
\textit{Materialized View}. Diese sind sehr ähnlich zu den Sichten, zusätzlich werden die Ergebnisse in einer
tabellenähnlichen Form abgespeichert. Somit sind die Zugriff auf diese Daten häufig performanter als die eigentliche Abfrage.
Daher muss abgewägt werden, ob die Performance-Verbesserung trotz der zusätzliche Aktualisierung des Datenbestandes
als sinnvoll erachtet werden kann.
\mytodos{das doch wieder raus? oder nur das mit create statistics drin lassen}
Zusätzlich kann über die Systemtabelle \texttt{pg\_statistic} oder die lesbarere Systemsicht \texttt{pg\_stats} die
aktuelle statistischen Informationen über eine Tabelle und deren Spalten ermittelt werden. In dieser Tabelle werden
durch das \texttt{ANALYZE} beziehungsweise \texttt{VACUUM ANALYZE} Kommando die Informationen zum Anteil der
\texttt{NULL}"=Werte (null\_frac), Durchschnittlichen Größe (avg\_width), unterschiedlicher Werte (n\_distinct) und
weitere gesammelt und für die Erstellung der Abfragepläne verwendet \citep{PostgreS39:online}. Diese Information
sollte vor dem erstellen eines Index betrachtet werden.
Diese Informationen können noch durch das Kommando \texttt{CREATE STATISTICS} erweitert werden, für einen besseren
Abfrageplan. Das Aktivieren der zusätzlichen Statistiken sollte immer in Verbindung mit der Überprüfung des
Abfrageplans durchgeführt werden, um zu ermitteln inwieweit die Anpassung zu einer Optimierung und keiner
Verschlechterung führt.