mirror of
https://github.com/janishutz/eth-summaries.git
synced 2026-07-27 21:29:09 +02:00
[DMDB] Memory management
This commit is contained in:
+3
-2
@@ -1,5 +1,6 @@
|
||||
\subsubsection{Execution Model}
|
||||
There are a number of ways in which the execution can happen
|
||||
\label{sec:execution-models}
|
||||
There are a number of ways in which the execution can happen. More details can be found in section \ref{sec:execution-models-advanced}
|
||||
|
||||
|
||||
\paragraph{Materialization Model}
|
||||
@@ -28,4 +29,4 @@ This method is similar to the iterator model, but instead of a single tuple, the
|
||||
We can also use vector instructions on the batch of tuple, which reduces overhead by requiring fewer function and instruction calls.
|
||||
|
||||
Of course, the limitation here is that the hardware needs to support vector instructions, though nowadays that is hardly an issue,
|
||||
since AVX instructions are supported on CPUs as old as the Sandy Bridge Architecture (e.g. Intel Core i7-2600K) for Intel (2011) and Bulldozer (e.g. AMD FX-8100) for AMD (2011).
|
||||
since \acrshort{avxa} instructions are supported on CPUs as old as the Sandy Bridge Architecture (e.g. Intel Core i7-2600K) for Intel (2011) and Bulldozer (e.g. AMD FX-8100) for AMD (2011).
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
\subsubsection{Physical to logical storage}
|
||||
\begin{wrapfigure}[14]{r}[0cm]{0.3\textwidth}
|
||||
\begin{center}
|
||||
\includegraphics[width=0.25\columnwidth]{assets/db-system-entity-relationship.png}
|
||||
\end{center}
|
||||
\caption{Entity relationship diagram, where the crow's feet imply one-to-many relationships
|
||||
(Figure from \hlhref{https://docs.oracle.com/en/database/oracle/oracle-database/19/cncpt/img/cncpt227.gif}{Oracle Docs})}
|
||||
\label{fig:entity-relation-diagram}
|
||||
\end{wrapfigure}
|
||||
|
||||
To the left, in figure \ref{fig:entity-relation-diagram}, the relationship between the different storage
|
||||
abstractions are connected using crow's feet.
|
||||
|
||||
Since database tables often include large amounts of data, that would span many OS pages, thus database systems use blocks as opposed to OS pages.
|
||||
|
||||
|
||||
These database blocks are structured as follows:
|
||||
\begin{itemize}
|
||||
\item \bi{Header}: Contains the address and type of segment (that being index, table, etc)
|
||||
\item \bi{Table directory}: Contains the schema of the table stored in the block
|
||||
\item \bi{Row directory}: Contains pointers to the actual tuples stored in the block. Grows downwards (like the stack)
|
||||
\item \bi{Free Space}: Well... it's free real estate, isn't it?
|
||||
\item \bi{Row data}: The tuples stored in the block. Grows upwards (like the heap).
|
||||
The pointers in the row directory point here
|
||||
\end{itemize}
|
||||
|
||||
Typically, database systems allow inserts of new tuples until there is about 20\% of free space left.
|
||||
This space is allocated to allow for updates of existing tuples, as they may become larger.
|
||||
Thus, a larger storage footprint is used to prevent having to move all the data to a different location when the data block inevitably fills up,
|
||||
avoiding thrashing on the page.
|
||||
|
||||
Some systems even go a step further, only again unlocking a data block for writing if its used percentage falls below 40\%.
|
||||
|
||||
Of course, as with any storage system, fragmentation becomes an issue.
|
||||
Compaction is only done when the block has enough space for an \texttt{INSERT} or \texttt{UPDATE}, but the space is not contiguous.
|
||||
|
||||
An \texttt{UPDATE} may require that a tuple is moved into a different block. In that case, the tuple is inserted into a new block and a pointer is stored in the freed space.
|
||||
@@ -0,0 +1,37 @@
|
||||
\subsubsection{Record Layout}
|
||||
Each record (commonly called tuple) contains a header (which in turn contains validity flags for deletion,
|
||||
visibility information for concurrency control, bit maps for null values and more), and the non-null attributes, or pointer to those attributes.
|
||||
|
||||
Relational engines do not have to store the schema for the tuple inside of it because that is set globally for the entire table.
|
||||
|
||||
Schema-less systems however have to store that information because it can differ for each record.
|
||||
|
||||
|
||||
\paragraph{Optimizations}
|
||||
\begin{wrapfigure}{l}{0.35\textwidth}
|
||||
\begin{center}
|
||||
\includegraphics[width=0.3\columnwidth]{assets/db-system-record-ordering.png}
|
||||
\end{center}
|
||||
\caption{Record layouts in memory
|
||||
(Figure from Lecture 09, Slide 19)}
|
||||
\end{wrapfigure}
|
||||
It is crucial to store the data in a way that allows quick accesses and updates.
|
||||
|
||||
Each variable length attribute also has to store the length, so in a simple system we would simply store them together with the data.
|
||||
This however is not ideal for performance reasons (we have linear access time), thus we keep the fixed size part (attributes and lengths) at the start of the record
|
||||
and move the variable length part to the end, putting pointers after the length attributes that point to the end of the variable length region.
|
||||
Even more performance can be gained by reordering the attributes altogether, moving the variable length attributes to the very end and then applying the above optimization.
|
||||
|
||||
|
||||
\paragraph{Data Types}
|
||||
\begin{itemize}
|
||||
\item \bi{Integers}: Most \acrshort{dbms} use the same format as \texttt{C}.
|
||||
\item \bi{Real numbers}: Either in IEEE-754 (for variable precision) or using fixed point representations, which commonly are variable length,
|
||||
by storing all digits, plus where the decimal point is (they are NOT stored as strings)
|
||||
\item \bi{Strings} and \bi{BLOBs}: Store the length and the data
|
||||
\item \bi{Time}, \bi{Coordinates}, \bi{points}, \dots: System specific.
|
||||
\end{itemize}
|
||||
|
||||
For large attributes, commonly instead of storing the whole tuple, only the fixed length attributes of the tuples are stored directly in the block,
|
||||
with pointers to the rest of the attributes, that may also lay outside of the current block.
|
||||
BLOBs may also be \textit{very} large, taking up more than a single block.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
\subsubsection{Data in the blocks}
|
||||
The pages allocated to a given object (table, index, etc) are managed through lists, which are stored as part of the segment header
|
||||
\begin{figure}[h!]
|
||||
\begin{center}
|
||||
\includegraphics[width=0.9\columnwidth]{assets/db-system-page-lists.png}
|
||||
\end{center}
|
||||
\caption{Free/used lists in databases
|
||||
(Figure from Lecture 09, Slide 24)}
|
||||
\end{figure}
|
||||
|
||||
These lists can become a bottleneck, especially for transactions that result in modifications.
|
||||
There are some ways to improve the performance:
|
||||
\begin{itemize}
|
||||
\item We can use several free lists, so concurrent transactions can find free space in parallel, rather than having conflicts all the time
|
||||
\item Make the traversal of the list faster (sorting, etc)
|
||||
\item Make sure that holes can be found efficiently (store the available space in each page in incremental steps)
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\paragraph{Slotted Pages}
|
||||
To find tuples within pages, slotted pages are used often.
|
||||
In slotted pages, each page has a header containing checksum, version, transaction visibility, compression information, utilization, etc.
|
||||
|
||||
Then, each tuple gets an id (typically a block ID and an offset).
|
||||
|
||||
The page maintains a list of the ``slots'' (each slot is assigned to one tuple and thus the number of tuples in the pages is further constrained by the number of pages available).
|
||||
The offsets, or sometimes pointers, are stored at the beginning of each tuple.
|
||||
|
||||
Advantages of slotted pages are:
|
||||
\begin{itemize}
|
||||
\item storing tuples of different sizes (and variable length tuples)
|
||||
\item Each tuple gets a permanent tuple / record id, that does not change
|
||||
\item When data doesn't change, space is used efficiently
|
||||
\item When data \textit{does} change, we need to be careful
|
||||
\end{itemize}
|
||||
|
||||
Considerations for when data \textit{does} change:
|
||||
\begin{itemize}
|
||||
\item If a tuple is modified and becomes larger, the original space is used to store a pointer to the new location of the tuple
|
||||
\item If a tuple is deleted, we just remove the pointer
|
||||
\item If a tuple is modified and becomes smaller, leave the unnecessary space empty
|
||||
\item For insertion, we look for a page with enough free space and compact the page, if needed
|
||||
\end{itemize}
|
||||
|
||||
The percentage free measure is used to avoid fragmentation caused by pages running out of space to accommodate updates for tuples that become larger.
|
||||
Thus, some space is reserved for growing the tuples, rather than for inserting.
|
||||
|
||||
Without this measure, the block can constantly go from \texttt{FREE} to \texttt{USED} and back and forth.
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
\subsubsection{Row and Column Stores}
|
||||
\paragraph{Row Store}
|
||||
Here, as we have assumed thus far, tuples are stored with all their attributes together.
|
||||
This means that accesses to tuples is quick and easy.
|
||||
|
||||
This scheme is used by actual systems, but they also have many additional details added to improve management and speed.
|
||||
|
||||
A typical ideal application for a row store is Online Transaction Processing (OLTP).
|
||||
This is visible for example with banking applications, shopping carts, etc, where the operations mostly are on a single tuple.
|
||||
|
||||
However, for xomplex queries, the row store can become cumbersome.
|
||||
|
||||
|
||||
\paragraph{Column Store}
|
||||
This is where the column store comes in, in which the data is stored by columns.
|
||||
This obviously speeds up operations on the columns, as the access is very quick.
|
||||
|
||||
Column stores also have the advantage that they present the data exactly in the representation needed for \acrshort{simd} instructions such as \acrshort{avxa},
|
||||
which is now widely available on modern CPUs.
|
||||
|
||||
Modern database systems have started to adopt column stores to address the memory wall,
|
||||
since Column Stores are a more compact representation and cache lines are likely to bring the data we want to see,
|
||||
thus the cache utilization tends to be higher than with row stores.
|
||||
|
||||
Column store databases are today primarily used today for analytical databases and in-memory databases.
|
||||
|
||||
|
||||
An alternative is a hybrid approach, called \bi{Partition Attributes Across (PAX)} representation.
|
||||
There, each block contains several tuples, but it is organized as a column store.
|
||||
@@ -0,0 +1,66 @@
|
||||
\subsubsection{Execution Models}
|
||||
\label{sec:execution-models-advanced}
|
||||
We model execution as a tree of operators (as seen previously). At the root, we have the query results, at the leaves we have the tables.
|
||||
Typically, each operator has \textit{at most} two inputs from lower layers (join operators have two, the rest typically has one).
|
||||
|
||||
We remember that we can use any subtree of a query as input for the higher parts of the tree, since we can ``materialize'' the result as a table.
|
||||
|
||||
|
||||
\paragraph{Basic Execution Models}
|
||||
Each node (operator) in the tree operates independently, i.e. does input, putput, output.
|
||||
|
||||
Each operator can read their input tuples in one go, or one at a time and the same goes for the output.
|
||||
Some operators may also be \textit{blocking}, i.e. no result can be issued until all operations are completed.
|
||||
|
||||
|
||||
\paragraph{More advanced models}
|
||||
As a reminder, we already covered some aspects of three execution models in section \ref{sec:execution-models}.
|
||||
|
||||
|
||||
\subparagraph{Iterator Model}
|
||||
Some typical dataflow operators:
|
||||
\begin{itemize}
|
||||
\item \bi{Union}: read both sides, issue all tuples (if they have the same schema)
|
||||
\item \bi{Union without duplicates}: We first union, then we check for duplicates
|
||||
\item \bi{Select}: We apply a filter function to the tuples
|
||||
\item \bi{Projection}: For each tuple, we output only the specified attributes
|
||||
\item \bi{Join}: Trivial nested loop join
|
||||
\item \bi{Join with index on inner relation}: For all tuples, fetch matchin tuple in S <= another operator
|
||||
\end{itemize}
|
||||
|
||||
\shade{green}{Advantages}
|
||||
\begin{multicols}{2}
|
||||
\begin{itemize}
|
||||
\item Generic interface for all operators
|
||||
\item Easy to implement operators
|
||||
\item Supports buffer management strategies
|
||||
\item No overhead in terms of main memory
|
||||
\item Supports pipelining
|
||||
\item Supports parallelism and distribution
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
\shade{red}{Disadvantages}
|
||||
\begin{multicols}{2}
|
||||
\begin{itemize}
|
||||
\item High overhead of method calls
|
||||
\item Poor instruction cache locality
|
||||
\end{itemize}
|
||||
\end{multicols}
|
||||
|
||||
|
||||
\paragraph{Pull \& Push Mode}
|
||||
\inlinedefinition[Pull Mode] Intuitively like dynamic programming: Data is obtained by one operator through a function call to a lower operator.
|
||||
It is good for disk based systems and when data doesn't fit into memory and is also really easy to implement.
|
||||
|
||||
\inlinedefinition[Push Mode] This is the Pull Mode flipped on its head.
|
||||
While it \textit{can} be faster, there need to be buffers everywhere and it is significantly harder to implement.
|
||||
|
||||
|
||||
\paragraph{EXCHANGE operator}
|
||||
The \texttt{EXCHANGE} operator is useful for parallel processing, as it simply moves data from one place to another.
|
||||
This allows to parallelize a plan across one or more machines.
|
||||
|
||||
This can be implemented as a sort of ``driver'' on top of an operator, by calling \texttt{next()} on the operator a few times,
|
||||
collecting the results and sending them to the other side.
|
||||
The other side uses the data to respond to further next calls to the original operator.
|
||||
@@ -11,6 +11,11 @@
|
||||
\newpage
|
||||
\subsection{Database Engines}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/00_intro.tex}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/01_physical-logical.tex}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/02_record-layout.tex}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/03_data-in-blocks-and-pages.tex}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/04_row-vs-column-store.tex}
|
||||
\input{parts/03_systems/01_database-engines/00_memory/05_execution-models.tex}
|
||||
% \input{parts/03_systems/01_database-engines/00_memory/}
|
||||
% \input{parts/03_systems/01_database-engines/}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user