Daily CheckIn

This commit is contained in:
marcodn 2024-09-21 15:05:19 +02:00
parent a4b5e2db3d
commit c66fd89941
3 changed files with 164 additions and 103 deletions

View file

@ -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
der Objekte den Cache übersteigt, fällt die Verbesserung geringer aus.
\section{cached queries}
\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
@ -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
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}
\label{sec:performance-investigation-application:materialized-views}
@ -559,8 +485,10 @@ 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
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
\textit{SearchDocument}"=Klasse verwendet. Wie in \autoref{lst:sql-materialized-view} zu sehen, wurden zur
\mytodos{hier nochmal die referenz auf wedekind-repo einbauen}
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
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.
@ -647,7 +575,7 @@ LEFT JOIN sitecity sc ON sc.id = d.city_id;
\end{lstlisting}
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]
CREATE INDEX idx_searchdocument_documentid
@ -671,8 +599,8 @@ CREATE INDEX idx_searchdocument_documentcategory
ON searchdocument (documentcategory);
\end{lstlisting}
Für die Darstellung wurden die aktuell vorhandenen Elemente die die Liste der Dokumente anzeigt kopiert und auf die
neue SearchDocument"=Klasse angepasst.
Für die Datenermittlung wurden die notwendigen Teile aus dem Wedekind"=Projekt kopiert. Bei der Darstellung wurden die
vorhanden Elemente die die Liste der Dokumente anzeigt kopiert und auf die \textit{SearchDocument}"=Klasse angepasst.
% document, first/last, documentaddresseeperson, documentcoauthorperson, documentfacsimile und count
% document, count, first/last
@ -697,11 +625,11 @@ neue SearchDocument"=Klasse angepasst.
\label{tbl:measure-materialized-view}
\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
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
und der Koautoren komplett entfallen.
nur noch vier statt der 6 Abfragen an die Datenbank gestellt werden, da die Einzelabfragen für die Adressen der
Personen und der Koautoren komplett entfallen.
Nach dem der Quellcode nochmal untersucht wurde, konnte man festellen, dass bei jeder Anfrage die gleiche Bedingung
benötigt wurde. Da die Sicht nun explizit für dies Anfrage geschaffen wurde, wurde die Bedingungen nun direkt in die
@ -724,8 +652,8 @@ Nach dem Anpassungen haben sich dann die Werte aus \autoref{tbl:measure-material
\hline
\# & min & avg & max & \#"=avg & avg & start & stop & diff & min & avg & max & min & avg & max \\
\hline
1 & 241 & 348 & 859 & 16.8 & xxx & 896.0 & 932.4 & xxxx & 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 -
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 & 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 -
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 -
@ -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
\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
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
\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.
Wie schon ermittelt, benötigt das erstellen der Objekte den Großteil der Zeit für die Datenermittlung. Daher wurde die
bereitgestellt Klasse betrachtet und die wie mit Herrn Tobias Holstein ausgemacht, der JsonParser nochmal genauer
untersucht. Im ersten Schritt wird die Parse"=Funktion entfernt und die Seite nochmals aufgerufen. Durch diese
Umstellung fällt die Laufzeit der Datenermittlung auf circa 4 ms ab. Nun muss noch geprüft werden, welche Zeit nun der
Client zum parsen der \textit{Json}"=Daten benötigt. Hierfür werden die Daten in einem versteckten
\textbf{span}"=Element hinterlegt, wie es im \autoref{lst:jsf-datatable-json} zu sehen ist. Die hinterlegte
\textit{CSS}"=Klasse ist zum auffinden der Elemente für den späteren Javascript. Das \textbf{ajax}"=Element im Beispiel
ist notwendig, damit bei einem Seitenwechsel die gleiche Interpreter"=Funktion für die \textit{Json}"=Daten aufgerufen
wird, wie beim laden der Webseite.
\begin{lstlisting}[language=xml,caption={DataTable mit Json},label=lst:jsf-datatable-json]
<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>
\end{lstlisting}
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.
Die Interpreter"=Funktion, welche in JavaScript geschrieben ist, wird benötigt um die ie übertragenen
\textit{Json}"=Daten in eine darstelle Form zu bringen. Die Funktion aus dem \autoref{lst:jsf-datatable-json-convert}
ermittelt erst alle versteckten Elemente, parsed den Inhalt und erstellt neue \textit{HTML}"=Elemente mit dem
darzustellenden Inhalt. Zusätzlich wird noch eine Zeitmessung mit eingebaut, um die Laufzeit am Client für das Rendern
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) {
@ -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
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.

View file

@ -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.
\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}
\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}
\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
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.
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}
\label{sec.evaluation:result-optimization:materialized-view}
\label{sec:evaluation:result-optimization:materialized-view}
\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}

Binary file not shown.