Daily CheckIn
This commit is contained in:
parent
a4b5e2db3d
commit
c66fd89941
3 changed files with 164 additions and 103 deletions
|
@ -222,7 +222,7 @@ Der Vergleich zeigt, dass der Cache eine gute Optimierung bringt, aber dies nur
|
||||||
wieder die gleichen Objekte ermittelt werden. Sobald die Anfragen im Wechsel gerufen werden oder einfach nur die Menge
|
wieder die gleichen Objekte ermittelt werden. Sobald die Anfragen im Wechsel gerufen werden oder einfach nur die Menge
|
||||||
der Objekte den Cache übersteigt, fällt die Verbesserung geringer aus.
|
der Objekte den Cache übersteigt, fällt die Verbesserung geringer aus.
|
||||||
|
|
||||||
\section{cached queries}
|
\section{Cached Queries}
|
||||||
\label{sec:performance-investigation-application:cached-query}
|
\label{sec:performance-investigation-application:cached-query}
|
||||||
|
|
||||||
Über die Einstellung \textit{openjpa.""jdbc.""QuerySQLCache} wird der Cache für abfragen aktiviert. Hierbei können
|
Über die Einstellung \textit{openjpa.""jdbc.""QuerySQLCache} wird der Cache für abfragen aktiviert. Hierbei können
|
||||||
|
@ -473,80 +473,6 @@ Einstellung \textit{openjpa.""FetchPlan.""EagerFetchMode} liefert auch hier Opti
|
||||||
\textit{parallel} gestellt wird. Hier wird ebenfalls die Anzahl der Anfragen reduziert und damit auch die
|
\textit{parallel} gestellt wird. Hier wird ebenfalls die Anzahl der Anfragen reduziert und damit auch die
|
||||||
Geschwindigkeit optimiert.
|
Geschwindigkeit optimiert.
|
||||||
|
|
||||||
\section{Optimierung der Abfrage}
|
|
||||||
\label{sec:performance-investigation-application:optimizing-query}
|
|
||||||
|
|
||||||
Für die Optimierung der Abfrage werden diese zuerst mit \textit{explain}, wie in \autoref{lst:explain-diagnostic}
|
|
||||||
dargestellt, untersuchen. Für die einfachere Diagnose, wird der erstellte Plan Mithilfe von pev2
|
|
||||||
\citep{GitHubda51:online} visualisiert.
|
|
||||||
|
|
||||||
\begin{lstlisting}[language=SQL,caption={Explain für Diagnose},label=lst:explain-diagnostic]
|
|
||||||
explain (analyze, verbose, buffers, summary, format json)
|
|
||||||
select <Spalten>
|
|
||||||
from
|
|
||||||
public.document t0
|
|
||||||
left outer join public.historicalperson t1 on t0.authorperson_id = t1.id
|
|
||||||
left outer join public.sitecity t5 on t0.city_id = t5.id
|
|
||||||
left outer join public.appuser t6 on t0.editor_id = t6.id
|
|
||||||
left outer join public.extendedbiography t2 on t1.extendedbiography_id = t2.id
|
|
||||||
left outer join public.sitecity t3 on t1.sitecity_birth_id = t3.id
|
|
||||||
left outer join public.sitecity t4 on t1.sitecity_death_id = t4.id
|
|
||||||
left outer join public.appuserrole t7 on t6.appuserrole_id = t7.id
|
|
||||||
where (t0.validuntil > NOW()
|
|
||||||
and t0.ispublishedindb = true)
|
|
||||||
order by startyear DESC, startmonth DESC, startday DESC
|
|
||||||
limit 400;
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
Die erstellte Visualisierung der Abfrage ist in \autoref{fig:explain-visualize} zu sehen. In der Visualisierung wurde
|
|
||||||
die Darstellung der Kosten gewählt, da ein Vergleich auf Basis der Zeit sehr schwierig ist und von äußeren Faktoren
|
|
||||||
abhängt, wie zum Beispiel dem Cache. Die Kosten sind stabiler und hängen in erster Linie vom Datenbestand ab.
|
|
||||||
|
|
||||||
\begin{figure}[h!]
|
|
||||||
\includegraphics[width=\linewidth]{gfx/chapter05_ExplainVisualize.png}
|
|
||||||
\caption{Visualisierung EXPLAIN}
|
|
||||||
\label{fig:explain-visualize}
|
|
||||||
\end{figure}
|
|
||||||
|
|
||||||
In der Graphik ist zu sehen, dass zum einen die Hauptkosten im untersten Knoten \textit{Seq Scan} und einen der
|
|
||||||
obersten Knoten dem \textit{HashAggregate} liegen. Zusätzlich sieht man anhand der stärke von den Verbindungslinien der
|
|
||||||
Knoten, dass die Menge der Datensätze enorm hoch ist und dieser sich bis zum obersten Knoten durchzieht. Dies
|
|
||||||
bedeutet, dass die Einschränkung des Datenbestandes erst am Ende der Abfrage durchgeführt wird und diesbezüglich die
|
|
||||||
Dauer der Abfrage linear mit den Inhalt der \textit{document}"=Tabelle zusammenhängt. Des Weiteren wird für keine
|
|
||||||
Tabelle ein \textit{Index Scan} verwendet, sondern immer mit einem \textit{Seq Scan} gearbeitet, da durch das ermitteln
|
|
||||||
des kompletten Datenbestandes der Optimizer entscheidet, dass der komplette Scan der Tabelle kostengeringer ist, als
|
|
||||||
die Verwendung eines der vorhandenen Indexe. Dies kann durch den Befehl \lstinline[language=SQL]|SET enable_seqscan = off|
|
|
||||||
sehr einfach verifiziert werden. Damit wird die Verwendung von \textit{Seq Scan} deaktiviert und es wird dann ein
|
|
||||||
\textit{Index Scan} verwendet. Wenn man nun beide Pläne vergleicht sieht man die Erhöhung der Kosten bei der Verwendung
|
|
||||||
von \textit{Index Scan}.
|
|
||||||
|
|
||||||
Die beste Optimierung hierbei ist, die Menge der Datensätze so früh wie möglich einzuschränken. Da die Verwendung von
|
|
||||||
\textit{order by} innerhalb eines Sub"=Selects nicht erlaubt ist, verwenden wir hierfür eine \textit{Common Table
|
|
||||||
Expression}, wie es in \autoref{lst:explain-optimize-cte} zu sehen ist. Zusätzlich wurde noch ein Index auf der
|
|
||||||
\textit{document}"=Tabelle für die Spalten der Bedingung und der Sortierung gesetzt, wie in
|
|
||||||
\autoref{lst:explain-optimize-cte-idx} zur sehen.
|
|
||||||
|
|
||||||
\begin{lstlisting}[language=SQL,caption={Optimierung mit Common Table Expression},label=lst:explain-optimize-cte]
|
|
||||||
with doc_limit as (
|
|
||||||
select id
|
|
||||||
from public.document
|
|
||||||
where validuntil > now()
|
|
||||||
and ispublishedindb = true
|
|
||||||
order by startyear desc, startmonth desc, startday desc
|
|
||||||
limit 400
|
|
||||||
)
|
|
||||||
select *
|
|
||||||
from doc_limit t
|
|
||||||
join public.document t0 on t0.id = t.id
|
|
||||||
order by t0.startyear desc, t0.startmonth desc, t0.startday desc
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
\begin{lstlisting}[language=SQL,caption={Index für Common Table Expression},label=lst:explain-optimize-cte-idx]
|
|
||||||
create index idx_document_with_stmt on document using btree
|
|
||||||
( ispublishedindb, validuntil, startyear desc, startmonth desc
|
|
||||||
, startday desc, id );
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
\section{Materialized Views}
|
\section{Materialized Views}
|
||||||
\label{sec:performance-investigation-application:materialized-views}
|
\label{sec:performance-investigation-application:materialized-views}
|
||||||
|
|
||||||
|
@ -559,10 +485,12 @@ Der größte Nachteil dieser Sichten ist, dass sie zyklisch oder bei Datenänder
|
||||||
läuft der Datenbestand der Sicht und der zugrundeliegenden Abfrage auseinander. Da die Hauptarbeiten auf der Webseite
|
läuft der Datenbestand der Sicht und der zugrundeliegenden Abfrage auseinander. Da die Hauptarbeiten auf der Webseite
|
||||||
die Abfrage der Daten ist, und nicht das editieren, kann dieser Nachteil bei entsprechender Optimierung ignoriert werden.
|
die Abfrage der Daten ist, und nicht das editieren, kann dieser Nachteil bei entsprechender Optimierung ignoriert werden.
|
||||||
|
|
||||||
In diesem Test wurde die von Herrn Holstein bereitgestellte Materialized View inklusive der Trigger und der
|
\mytodos{hier nochmal die referenz auf wedekind-repo einbauen}
|
||||||
\textit{SearchDocument}"=Klasse verwendet. Wie in \autoref{lst:sql-materialized-view} zu sehen, wurden zur
|
|
||||||
|
In diesem Test wurde die aktuelle Implementierung aus dem Wedekind"=Projekt der Materialized View inklusive der Trigger
|
||||||
|
und der \textit{SearchDocument}"=Klasse übernommen. Wie in \autoref{lst:sql-materialized-view} zu sehen, wurden zur
|
||||||
Standard"=Abfrage, die sonst zusätzlichen Abfragen als direkte Sub"=Selects mit integriert. Der Datenbestand dieser
|
Standard"=Abfrage, die sonst zusätzlichen Abfragen als direkte Sub"=Selects mit integriert. Der Datenbestand dieser
|
||||||
Sub"=Selects, wird im Json"=Format angegeben, damit bei den Koautoren und den Adressen mehrere Datensätze in einer
|
Sub"=Selects, wird im Json"=Format angegeben, damit bei den Koautoren und den Adressen mehrere Datensätze in einer
|
||||||
Zeile zurückgegeben werden können. Ohne diese Technik würde sich die Anzahl der Dokumente vervielfachen.
|
Zeile zurückgegeben werden können. Ohne diese Technik würde sich die Anzahl der Dokumente vervielfachen.
|
||||||
|
|
||||||
\begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view]
|
\begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view]
|
||||||
|
@ -647,7 +575,7 @@ LEFT JOIN sitecity sc ON sc.id = d.city_id;
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
Zusätzlich zur View, werden noch die Indexe aus \autoref{lst:sql-materialized-view-index} erstellt. Diese werden für
|
Zusätzlich zur View, werden noch die Indexe aus \autoref{lst:sql-materialized-view-index} erstellt. Diese werden für
|
||||||
für eine bessere Performance der Abfrage benötigt.
|
eine bessere Performance der Abfrage benötigt.
|
||||||
|
|
||||||
\begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view-index]
|
\begin{lstlisting}[language=SQL,caption={SQL Materialized View},label=lst:sql-materialized-view-index]
|
||||||
CREATE INDEX idx_searchdocument_documentid
|
CREATE INDEX idx_searchdocument_documentid
|
||||||
|
@ -671,8 +599,8 @@ CREATE INDEX idx_searchdocument_documentcategory
|
||||||
ON searchdocument (documentcategory);
|
ON searchdocument (documentcategory);
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
Für die Darstellung wurden die aktuell vorhandenen Elemente die die Liste der Dokumente anzeigt kopiert und auf die
|
Für die Datenermittlung wurden die notwendigen Teile aus dem Wedekind"=Projekt kopiert. Bei der Darstellung wurden die
|
||||||
neue SearchDocument"=Klasse angepasst.
|
vorhanden Elemente die die Liste der Dokumente anzeigt kopiert und auf die \textit{SearchDocument}"=Klasse angepasst.
|
||||||
|
|
||||||
% document, first/last, documentaddresseeperson, documentcoauthorperson, documentfacsimile und count
|
% document, first/last, documentaddresseeperson, documentcoauthorperson, documentfacsimile und count
|
||||||
% document, count, first/last
|
% document, count, first/last
|
||||||
|
@ -697,11 +625,11 @@ neue SearchDocument"=Klasse angepasst.
|
||||||
\label{tbl:measure-materialized-view}
|
\label{tbl:measure-materialized-view}
|
||||||
\end{table}
|
\end{table}
|
||||||
|
|
||||||
Wie in \autoref{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 eine Verbesserung
|
||||||
in verschiedenen Punkten. Zum einen ist eine Verbesserung der Aufrufzeiten zu erkennen, zusätzlich fällt der
|
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
|
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
|
nur noch vier statt der 6 Abfragen an die Datenbank gestellt werden, da die Einzelabfragen für die Adressen der
|
||||||
und der Koautoren komplett entfallen.
|
Personen und der Koautoren komplett entfallen.
|
||||||
|
|
||||||
Nach dem der Quellcode nochmal untersucht wurde, konnte man festellen, dass bei jeder Anfrage die gleiche Bedingung
|
Nach dem der Quellcode nochmal untersucht wurde, konnte man festellen, dass bei jeder Anfrage die gleiche Bedingung
|
||||||
benötigt wurde. Da die Sicht nun explizit für dies Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die
|
benötigt wurde. Da die Sicht nun explizit für dies Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die
|
||||||
|
@ -724,8 +652,8 @@ Nach dem Anpassungen haben sich dann die Werte aus \autoref{tbl:measure-material
|
||||||
\hline
|
\hline
|
||||||
\# & min & avg & max & \#"=avg & avg & start & stop & diff & min & avg & max & min & avg & max \\
|
\# & min & avg & max & \#"=avg & avg & start & stop & diff & min & avg & max & min & avg & max \\
|
||||||
\hline
|
\hline
|
||||||
1 & 241 & 348 & 859 & 16.8 & xxx & 896.0 & 932.4 & xxxx & 232 & 331 & 803 & 132 & 174 & 334 \\ % 168 -
|
1 & 241 & 348 & 859 & 16.8 & xxx & 896.0 & 932.4 & 36.4 & 232 & 331 & 803 & 132 & 174 & 334 \\ % 168 -
|
||||||
2 & 164 & 194 & 225 & 9.0 & xxx & 933.3 & 935.9 & xxxx & 154 & 185 & 215 & 79 & 99 & 117 \\ % 258 -
|
2 & 164 & 194 & 225 & 9.0 & xxx & 933.3 & 935.9 & 2.6 & 154 & 185 & 215 & 79 & 99 & 117 \\ % 258 -
|
||||||
3 & 147 & 161 & 179 & 9.0 & xxx & 935.8 & 938.8 & 3.0 & 139 & 152 & 167 & 68 & 77 & 86 \\ % 348 -
|
3 & 147 & 161 & 179 & 9.0 & xxx & 935.8 & 938.8 & 3.0 & 139 & 152 & 167 & 68 & 77 & 86 \\ % 348 -
|
||||||
4 & 135 & 145 & 183 & 9.0 & xxx & 939.4 & 936.0 & -3.4 & 127 & 137 & 174 & 70 & 73 & 75 \\ % 438 -
|
4 & 135 & 145 & 183 & 9.0 & xxx & 939.4 & 936.0 & -3.4 & 127 & 137 & 174 & 70 & 73 & 75 \\ % 438 -
|
||||||
5 & 126 & 137 & 154 & 9.0 & xxx & 936.1 & 939.1 & 3.0 & 118 & 129 & 143 & 66 & 72 & 79 \\ % 528 -
|
5 & 126 & 137 & 154 & 9.0 & xxx & 936.1 & 939.1 & 3.0 & 118 & 129 & 143 & 66 & 72 & 79 \\ % 528 -
|
||||||
|
@ -756,13 +684,15 @@ Das aktivieren der Cache"=Optionen wie in \autoref{sec:performance-investigation
|
||||||
Dies ist dadurch erklärbar, da keine Objekte durch das OpenJPA"=Framework erstellt werden, sondern erst in der
|
Dies ist dadurch erklärbar, da keine Objekte durch das OpenJPA"=Framework erstellt werden, sondern erst in der
|
||||||
\textit{map}"=Funktion des eigenen Codes.
|
\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
|
Wie schon ermittelt, benötigt das erstellen der Objekte den Großteil der Zeit für die Datenermittlung. Daher wurde die
|
||||||
die Parse-Funktion auskommentiert und die Seite nochmal aufgerufen. Durch diese Umstellung fällt die Laufzeit der
|
bereitgestellt Klasse betrachtet und die wie mit Herrn Tobias Holstein ausgemacht, der JsonParser nochmal genauer
|
||||||
Datenermittlung auf circa 4 ms ab. Nun muss noch geprüft werden, welche Zeit nun der Client zum parsen der
|
untersucht. Im ersten Schritt wird die Parse"=Funktion entfernt und die Seite nochmals aufgerufen. Durch diese
|
||||||
\textit{Json}"=Daten benötigt. Hierfür werden die Daten in einem versteckten \textbf{span}"=Element hinterlegt, wie es
|
Umstellung fällt die Laufzeit der Datenermittlung auf circa 4 ms ab. Nun muss noch geprüft werden, welche Zeit nun der
|
||||||
im \autoref{lst:jsf-datatable-json} zu sehen ist. Die hinterlegte \textit{CSS}"=Klasse ist zum auffinden der Elemente
|
Client zum parsen der \textit{Json}"=Daten benötigt. Hierfür werden die Daten in einem versteckten
|
||||||
für den späteren Javascript. Das \textbf{ajax}"=Element im Beispiel ist notwendig, damit bei einem Seitenwechsel die neu
|
\textbf{span}"=Element hinterlegt, wie es im \autoref{lst:jsf-datatable-json} zu sehen ist. Die hinterlegte
|
||||||
übertragenen Elemente in eine lesbare Form gebracht werden.
|
\textit{CSS}"=Klasse ist zum auffinden der Elemente für den späteren Javascript. Das \textbf{ajax}"=Element im Beispiel
|
||||||
|
ist notwendig, damit bei einem Seitenwechsel die gleiche Interpreter"=Funktion für die \textit{Json}"=Daten aufgerufen
|
||||||
|
wird, wie beim laden der Webseite.
|
||||||
|
|
||||||
\begin{lstlisting}[language=xml,caption={DataTable mit Json},label=lst:jsf-datatable-json]
|
\begin{lstlisting}[language=xml,caption={DataTable mit Json},label=lst:jsf-datatable-json]
|
||||||
<p:ajax event="page" oncomplete="convertJsonData()"/>
|
<p:ajax event="page" oncomplete="convertJsonData()"/>
|
||||||
|
@ -777,11 +707,11 @@ für den späteren Javascript. Das \textbf{ajax}"=Element im Beispiel ist notwen
|
||||||
</p:column>
|
</p:column>
|
||||||
\end{lstlisting}
|
\end{lstlisting}
|
||||||
|
|
||||||
Um nun die übertragenen \textit{Json}"=Daten in eine darstellbare Form zu bringen, benötigt man noch eine
|
Die Interpreter"=Funktion, welche in JavaScript geschrieben ist, wird benötigt um die ie übertragenen
|
||||||
JavaScript"=Funktion. Die Funktion aus \autoref{lst:jsf-datatable-json-convert} ermittelt erst alle versteckten
|
\textit{Json}"=Daten in eine darstelle Form zu bringen. Die Funktion aus dem \autoref{lst:jsf-datatable-json-convert}
|
||||||
Elemente, parsed den Inhalt und erstellt neue \textit{HTML}"=Elemente mit dem darzustellenden Inhalt. Zusätzlich wird
|
ermittelt erst alle versteckten Elemente, parsed den Inhalt und erstellt neue \textit{HTML}"=Elemente mit dem
|
||||||
noch eine Zeitmessung mit eingebaut, um die Laufzeit am Client für das Rendern in der Konsole anzuzeigen. Die Funktion
|
darzustellenden Inhalt. Zusätzlich wird noch eine Zeitmessung mit eingebaut, um die Laufzeit am Client für das Rendern
|
||||||
wird nun direkt nach dem die Webseite fertig geladen wurde aufgerufen.
|
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]
|
\begin{lstlisting}[language=javascript,caption={Wandeln von Json nach Html},label=lst:jsf-datatable-json-convert]
|
||||||
function isEmpty(str) {
|
function isEmpty(str) {
|
||||||
|
@ -829,4 +759,93 @@ 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
|
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.
|
Lösung auf eine kürzere Laufzeit und weniger Last am Server.
|
||||||
|
|
||||||
\mytodos{Grundlagen zur Materialized-View noch hinterlegen}
|
\section{Optimierung der Abfrage}
|
||||||
|
\label{sec:performance-investigation-application:optimizing-query}
|
||||||
|
|
||||||
|
Für die Optimierung der Abfrage werden diese zuerst mit \textit{explain}, wie in \autoref{lst:explain-diagnostic}
|
||||||
|
dargestellt, untersuchen. Für die einfachere Diagnose, wird der erstellte Plan Mithilfe von pev2
|
||||||
|
\citep{GitHubda51:online} visualisiert.
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=SQL,caption={Explain für Diagnose},label=lst:explain-diagnostic]
|
||||||
|
explain (analyze, verbose, buffers, summary, format json)
|
||||||
|
select <Spalten>
|
||||||
|
from
|
||||||
|
public.document t0
|
||||||
|
left outer join public.historicalperson t1 on t0.authorperson_id = t1.id
|
||||||
|
left outer join public.sitecity t5 on t0.city_id = t5.id
|
||||||
|
left outer join public.appuser t6 on t0.editor_id = t6.id
|
||||||
|
left outer join public.extendedbiography t2 on t1.extendedbiography_id = t2.id
|
||||||
|
left outer join public.sitecity t3 on t1.sitecity_birth_id = t3.id
|
||||||
|
left outer join public.sitecity t4 on t1.sitecity_death_id = t4.id
|
||||||
|
left outer join public.appuserrole t7 on t6.appuserrole_id = t7.id
|
||||||
|
where (t0.validuntil > NOW()
|
||||||
|
and t0.ispublishedindb = true)
|
||||||
|
order by startyear DESC, startmonth DESC, startday DESC
|
||||||
|
limit 400;
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Die erstellte Visualisierung der Abfrage ist in \autoref{fig:explain-visualize} zu sehen. In der Visualisierung wurde
|
||||||
|
die Darstellung der Kosten gewählt, da ein Vergleich auf Basis der Zeit sehr schwierig ist und von äußeren Faktoren
|
||||||
|
abhängt, wie zum Beispiel dem Cache. Die Kosten sind stabiler und hängen in erster Linie vom Datenbestand ab.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\includegraphics[width=\linewidth]{gfx/chapter05_ExplainVisualize.png}
|
||||||
|
\caption{Visualisierung EXPLAIN}
|
||||||
|
\label{fig:explain-visualize}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
In der Graphik ist zu sehen, dass zum einen die Hauptkosten im untersten Knoten \textit{Seq Scan} und einen der
|
||||||
|
obersten Knoten dem \textit{HashAggregate} liegen. Zusätzlich sieht man anhand der stärke von den Verbindungslinien der
|
||||||
|
Knoten, dass die Menge der Datensätze enorm hoch ist und dieser sich bis zum obersten Knoten durchzieht. Dies
|
||||||
|
bedeutet, dass die Einschränkung des Datenbestandes erst am Ende der Abfrage durchgeführt wird und diesbezüglich die
|
||||||
|
Dauer der Abfrage linear mit den Inhalt der \textit{document}"=Tabelle zusammenhängt. Des Weiteren wird für keine
|
||||||
|
Tabelle ein \textit{Index Scan} verwendet, sondern immer mit einem \textit{Seq Scan} gearbeitet, da durch das ermitteln
|
||||||
|
des kompletten Datenbestandes der Optimizer entscheidet, dass der komplette Scan der Tabelle kostengünstiger ist, als
|
||||||
|
die Verwendung eines der vorhandenen Indexe. Dies kann durch den Befehl \lstinline[language=SQL]|SET enable_seqscan = off|
|
||||||
|
sehr einfach verifiziert werden. Damit wird die Verwendung von \textit{Seq Scan} deaktiviert und es wird dann ein
|
||||||
|
\textit{Index Scan} verwendet. Wenn man nun beide Pläne vergleicht sieht man die Erhöhung der Kosten bei der Verwendung
|
||||||
|
von \textit{Index Scan}.
|
||||||
|
|
||||||
|
Die beste Optimierung hierbei ist, die Menge der Datensätze so früh wie möglich einzuschränken. Da die Verwendung von
|
||||||
|
\textit{order by} innerhalb eines Sub"=Selects nicht erlaubt ist, verwenden wir hierfür eine \textit{Common Table
|
||||||
|
Expression}, wie es in \autoref{lst:explain-optimize-cte} zu sehen ist. Zusätzlich wurde noch ein Index auf der
|
||||||
|
\textit{document}"=Tabelle für die Spalten der Bedingung und der Sortierung gesetzt, wie in
|
||||||
|
\autoref{lst:explain-optimize-cte-idx} zur sehen, damit in der \textit{Common Table Expression} nur der Index verwendet
|
||||||
|
werden kann und kein zusätzlicher Zugriff in die Tabelle notwendig ist.
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=SQL,caption={Optimierung mit Common Table Expression},label=lst:explain-optimize-cte]
|
||||||
|
with doc_limit as (
|
||||||
|
select id
|
||||||
|
from public.document
|
||||||
|
where validuntil > now()
|
||||||
|
and ispublishedindb = true
|
||||||
|
order by startyear desc, startmonth desc, startday desc
|
||||||
|
limit 400
|
||||||
|
)
|
||||||
|
select *
|
||||||
|
from doc_limit t
|
||||||
|
join public.document t0 on t0.id = t.id
|
||||||
|
order by t0.startyear desc, t0.startmonth desc, t0.startday desc
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
\begin{lstlisting}[language=SQL,caption={Index für Common Table Expression},label=lst:explain-optimize-cte-idx]
|
||||||
|
create index idx_document_with_stmt on document using btree
|
||||||
|
( ispublishedindb, validuntil, startyear desc, startmonth desc
|
||||||
|
, startday desc, id );
|
||||||
|
\end{lstlisting}
|
||||||
|
|
||||||
|
Mit diesen Umstellungen erkennt man nun, dass die Kosten entsprechend gefallen sind. Ebenfalls konnten die Laufzeit um
|
||||||
|
mehr als den Faktor drei reduziert werden. Die Optimierung ist in \autoref{fig:explain-visualize-with} sehr deutlich
|
||||||
|
an dein dünneren Verbindungslinien zwischen den Knoten und der Umstellung von einigen \textit{Seq Scan} zu
|
||||||
|
\textit{Index Scan} ersichtlich. Zeitgleich ist auch der teure \textit{HashAggregate} nicht mehr im Abfrageplan
|
||||||
|
vorhanden.
|
||||||
|
|
||||||
|
\begin{figure}[h!]
|
||||||
|
\includegraphics[width=\linewidth]{gfx/chapter05_ExplainVisualize_with.png}
|
||||||
|
\caption{Visualisierung EXPLAIN with}
|
||||||
|
\label{fig:explain-visualize-with}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
Bei der Untersuchung der Abfrage zur Materialized View ist direkt herausgekommen, dass hier keine Optimierung mehr
|
||||||
|
möglich ist, da durch die definierten Index bei den aktuell möglichen Sortierkriterien direkt ein \textit{Index Scan}
|
||||||
|
verwendet wird. Damit ist der schnellstmögliche Zugriff gegeben.
|
||||||
|
|
|
@ -91,10 +91,35 @@ werden. Dies ist der Grund warum diese Anfragen in diesem Cache nicht gespeicher
|
||||||
|
|
||||||
Dadurch ist dieser Cache für eine Performance"=Verbesserung in unseren Fall nicht verwendbar.
|
Dadurch ist dieser Cache für eine Performance"=Verbesserung in unseren Fall nicht verwendbar.
|
||||||
|
|
||||||
|
\subsection{Caching mit Ehcache}
|
||||||
|
\label{sec:evaluation:result-optimization:ehcache}
|
||||||
|
|
||||||
|
\mytodos{fehlt noch}
|
||||||
|
Mit dem Ehcache konnte eine Verbesserung in der Performance erzielt werden. Im Vergleich zum Cache von OpenJPA sind
|
||||||
|
die Verbesserung sehr ähnlich. Die Standardwerte dieses Caches sind gut vordefiniert, es wird für den aktuellen Fall
|
||||||
|
keine Anpassung benötigt um eine gute Performance zu bekommen. Hierbei ist natürlich das gleiche Problem wie in anderen
|
||||||
|
Caches, dass beim erreichen der Grenzen, alte Objekte entfernt werden müssen.
|
||||||
|
|
||||||
|
Nach aktueller Beobachtung scheint die Verwaltung im Ehcache effizienter gestaltet zu sein, als die des OpenJPA"=Caches.
|
||||||
|
Im Falle des Ehcache ist die interne Verwaltung auf mehrere Caches aufgebaut, dies ist daran zu sehen, dass in der
|
||||||
|
Standardkonfiguration jede Klasse ihren eigenen Cache besitzt. Diese können einzeln konfiguriert und diagnostiziert
|
||||||
|
werden, um diese genau auf die jeweiligen Bedürfnisse der Objekte anzupassen.
|
||||||
|
|
||||||
|
Im Falle der Verwendung des Caches, ist auch hier gut zu sehen, dass der Speicheranstieg bei der Verwendung des Caches
|
||||||
|
sehr gering ist, was den Schluss zu lässt, dass der Cache nur zu einem kleinen
|
||||||
|
|
||||||
|
Durch die effizienter Verwendung des Speichers, ist der Ehcache die bessere Alternative zum OpenJPA"=Cache. Dieser ist
|
||||||
|
auch schon für kleinere Serverkonfigurationen gut verwendbar. Hierbei ist nur abzuwägen, mit welcher Größe der Cache
|
||||||
|
bereitgestellt werden kann, was direkt am verfügbaren Arbeitsspeicher abhängt.
|
||||||
|
|
||||||
\subsection{Caching in EJB}
|
\subsection{Caching in EJB}
|
||||||
\label{sec:evaluation:result-optimization:ejb}
|
\label{sec:evaluation:result-optimization:ejb}
|
||||||
|
|
||||||
\mytodos{fehlt noch}
|
Bei der Erweiterung des EJB konnte keine Verbesserung in der Performance festgestellt werden. Dies liegt daran, dass
|
||||||
|
im EJB"=Cache die Provider beinhaltet, aber keine Daten"=Objekte. Dadurch kann der Cache das ermitteln der Objekte
|
||||||
|
nicht optimieren.
|
||||||
|
|
||||||
|
Aufgrund dessen ist der EJB"=Cache nicht für eine Performance"=Verbesserung nutzbar.
|
||||||
|
|
||||||
\subsection{Abfragen mit JPQL und Criteria API}
|
\subsection{Abfragen mit JPQL und Criteria API}
|
||||||
\label{sec:evaluation:result-optimization:jpal-capi}
|
\label{sec:evaluation:result-optimization:jpal-capi}
|
||||||
|
@ -121,9 +146,26 @@ jeweiligen Einsatzzweck besser beziehungsweise einfacher zu programmieren ist. D
|
||||||
ist in beiden Fällen äußerst wichtig. Explizit der EagerFetchMode muss vorher darüber nachgedacht werden, wie viele
|
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
|
abhängige Objekttypen es zu dieser Klasse gibt, welche dazu geladen werden sollen und von welcher Anzahl an Objekte
|
||||||
ausgegangen werden kann. Gerade bei ein größeren Anzahl lohnt es sich den Hint auf \textit{parallel} zu setzen.
|
ausgegangen werden kann. Gerade bei 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.
|
Gleiches gilt den Hint SubclassFetchMode, dieser steuert dimensionierten Abfragen im falle von abgeleitet Klassen.
|
||||||
|
|
||||||
\subsection{Materialized View}
|
\subsection{Materialized View}
|
||||||
\label{sec.evaluation:result-optimization:materialized-view}
|
\label{sec:evaluation:result-optimization:materialized-view}
|
||||||
|
|
||||||
\mytodos{hier weiter machen}
|
\mytodos{hier weiter machen}
|
||||||
|
Mit der Verwendung der Materialisierten Sichten können
|
||||||
|
Die Idee der Materialisierten Sichten ist simple aber sehr effizient, gerade für einen Datenbestand der häufig gelesen
|
||||||
|
und selten verändert wird. Hierbei werden komplexe Abfragen einmalig ausgeführt und das Ergebnis intern
|
||||||
|
zwischengespeichert wird. Für alle weiteren Aufrufe, werden die Daten nun aus der Sicherung gelesen. Technisch gesehen
|
||||||
|
könnte dies auch selbständig implementiert werden, in dem zyklisch oder ereignisgesteuert das Ergebnis der Abfrage in
|
||||||
|
eine Tabelle gespeichert wird.
|
||||||
|
|
||||||
|
Der Vorteil der Materialisierten Sichten ist, dass es einfach zu implementieren ist, eine geringere Fehleranfälligkeit
|
||||||
|
aufweist und , da alles über die reine Sichtdefinition erstellt wird. Ebenfalls
|
||||||
|
|
||||||
|
% verweisen auf doppelte Speicherung, ist zwar im cache das gleich, aber abzuwägen an welcher Stelle "mehr" zur
|
||||||
|
% verfügung steht bzw. welcher Part günstiger in der Bereitstellung ist
|
||||||
|
|
||||||
|
\subsection{Optimierung der Abfrage}
|
||||||
|
\label{sec:evaluation:result-optimization:optimize-query}
|
||||||
|
|
||||||
|
\mytodos{fehlt noch}
|
||||||
|
|
BIN
thesis.pdf
BIN
thesis.pdf
Binary file not shown.
Loading…
Reference in a new issue