mirror of
https://github.com/kristoferssolo/Databases-II-Cheatsheet.git
synced 2025-10-21 18:20:35 +00:00
refactor: use columns
This commit is contained in:
parent
a9bb553cf3
commit
928bd8554f
358
main.typ
358
main.typ
@ -1,34 +1,34 @@
|
|||||||
#set page(margin: (
|
#import "@preview/tablex:0.0.8": tablex, rowspanx, colspanx
|
||||||
top: 0.6cm,
|
#set page(margin: 0.6cm, columns: 3)
|
||||||
bottom: 0.6cm,
|
|
||||||
right: 0.6cm,
|
|
||||||
left: 0.6cm,
|
|
||||||
))
|
|
||||||
|
|
||||||
#set text(6.2pt)
|
#set text(6pt)
|
||||||
#show heading: it => {
|
#show heading: it => {
|
||||||
if it.level == 1 {
|
if it.level == 1 {
|
||||||
// pagebreak(weak: true)
|
text(1em, upper(it))
|
||||||
text(8.5pt, upper(it))
|
|
||||||
} else if it.level == 2 {
|
|
||||||
text(8pt, smallcaps(it))
|
|
||||||
} else {
|
} else {
|
||||||
text(8pt, smallcaps(it))
|
text(1em, smallcaps(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#set enum(numbering: "1aiA.")
|
||||||
= Indices
|
= Indices
|
||||||
|
|
||||||
== Bitmap
|
== Bitmap
|
||||||
|
|
||||||
Each bit in a bitmap corresponds to a possible item or condition, with a bit
|
Each bit in a bitmap corresponds to a possible item or condition, with a bit set
|
||||||
set to 1 indicating presence or true, and a bit set to 0 indicating absence or
|
to 1 indicating presence or true, and a bit set to 0 indicating absence or
|
||||||
false.
|
false.
|
||||||
|
|
||||||
#figure(
|
#tablex(
|
||||||
image("img/bitmap.png", width: 30%)
|
stroke: 0.5pt, columns: 4, [record number], `ID`, `gender`, `income_level`, `0`, `76766`, `m`, `L1`, `1`, `22222`, `f`, `L2`, `2`, `12121`, `f`, `L1`, `3`, `15151`, `m`, `L4`, `4`, `58583`, `f`, `L3`,
|
||||||
)
|
)
|
||||||
|
#grid(
|
||||||
|
columns: 3, gutter: 2em, tablex(
|
||||||
|
stroke: 0.5pt, columns: 2, colspanx(2)[Bitmaps for `gender`], `m`, `10010`, `f`, `01101`,
|
||||||
|
), tablex(
|
||||||
|
stroke: 0.5pt, columns: 2, colspanx(2)[Bitmaps for `income_level`], `L1`, `10010`, `L2`, `01000`, `L3`, `00001`, `L4`, `00010`, `L5`, `00000`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
== B+ tree
|
== B+ tree
|
||||||
|
|
||||||
@ -38,32 +38,32 @@ logarithmic time. It is an extension of the B-tree and is extensively used in
|
|||||||
databases and filesystems for indexing. B+ tree is *Balanced*; Order (n):
|
databases and filesystems for indexing. B+ tree is *Balanced*; Order (n):
|
||||||
Defined such that each node (except root) can have at most $n$ children
|
Defined such that each node (except root) can have at most $n$ children
|
||||||
(pointers) and at least $⌈n/2⌉$ children; *Internal nodes hold* between
|
(pointers) and at least $⌈n/2⌉$ children; *Internal nodes hold* between
|
||||||
$⌈n/2⌉−1$ and $n−1$ keys (values); Leaf nodes hold between $⌈frac(n −1,2)⌉$ and
|
$⌈n/2⌉−1$ and $n−1$ keys (values); Leaf nodes hold between $⌈frac(n −1, 2)⌉$ and
|
||||||
$n−1$ keys, but also store all data values corresponding to the keys; *Leaf
|
$n−1$ keys, but also store all data values corresponding to the keys; *Leaf
|
||||||
Nodes Linked*: Leaf nodes are linked together, making range queries and
|
Nodes Linked*: Leaf nodes are linked together, making range queries and
|
||||||
sequential access very efficient.
|
sequential access very efficient.
|
||||||
|
|
||||||
- *Insert (key, data)*:
|
- *Insert (key, data)*:
|
||||||
- Insert key in the appropriate leaf node in sorted order;
|
- Insert key in the appropriate leaf node in sorted order;
|
||||||
- If the node overflows (more than $n−1$ keys), split it, add the middle
|
- If the node overflows (more than $n−1$ keys), split it, add the middle key to
|
||||||
key to the parent, and adjust pointers;
|
the parent, and adjust pointers;
|
||||||
+ Leaf split: $1$ to $ceil(frac(n,2)) $ and $ceil(frac(n,2)) + 1 $ to
|
+ Leaf split: $1$ to $ceil(frac(n, 2)) $ and $ceil(frac(n, 2)) + 1 $ to
|
||||||
$n$ as two leafs. Promote the lowest from the 2nd one.
|
$n$ as two leafs. Promote the lowest from the 2nd one.
|
||||||
+ Node split: $1$ to $ceil(frac(n+1, 2)) - 1 $ and $ceil(frac(n,2)) + 1$ to $n$.
|
+ Node split: $1$ to $ceil(frac(n+1, 2)) - 1 $ and $ceil(frac(n, 2)) + 1$ to $n$.
|
||||||
$ceil(frac(n+1, 2))$ gets moved up.
|
$ceil(frac(n+1, 2))$ gets moved up.
|
||||||
- If a split propagates to the root and causes the root to overflow, split
|
- If a split propagates to the root and causes the root to overflow, split the
|
||||||
the root and create a new root. Note: root can contain less than
|
root and create a new root. Note: root can contain less than
|
||||||
$ceil(frac(n,2)) - 1$ keys.
|
$ceil(frac(n, 2)) - 1$ keys.
|
||||||
- *Delete (key)*:
|
- *Delete (key)*:
|
||||||
- Remove the key from the leaf node.
|
- Remove the key from the leaf node.
|
||||||
- If the node underflows (fewer than $⌈n/2⌉−1$ keys), keys and pointers are
|
- If the node underflows (fewer than $⌈n/2⌉−1$ keys), keys and pointers are
|
||||||
redistributed or nodes are merged to maintain minimum occupancy. -
|
redistributed or nodes are merged to maintain minimum occupancy. -
|
||||||
Adjustments may propagate up to ensure all properties are maintained.
|
Adjustments may propagate up to ensure all properties are maintained.
|
||||||
|
|
||||||
== Hash-index
|
== Hash-index
|
||||||
|
|
||||||
*Hash indices* are a type of database index that uses a hash function to
|
*Hash indices* are a type of database index that uses a hash function to compute
|
||||||
compute the location (hash value) of data items for quick retrieval. They are
|
the location (hash value) of data items for quick retrieval. They are
|
||||||
particularly efficient for equality searches that match exact values.
|
particularly efficient for equality searches that match exact values.
|
||||||
|
|
||||||
*Hash Function*: A hash function takes a key (a data item's attribute used for
|
*Hash Function*: A hash function takes a key (a data item's attribute used for
|
||||||
@ -73,18 +73,16 @@ position in the hash table where the corresponding record's pointer is stored.
|
|||||||
database. Each entry in the hash table corresponds to a potential hash value
|
database. Each entry in the hash table corresponds to a potential hash value
|
||||||
generated by the hash function.
|
generated by the hash function.
|
||||||
|
|
||||||
= Algorithms
|
= Algorithms
|
||||||
|
|
||||||
|
|
||||||
== Nested-loop join
|
== Nested-loop join
|
||||||
|
|
||||||
*Nested Loop Join*: A nested loop join is a database join operation where each
|
*Nested Loop Join*: A nested loop join is a database join operation where each
|
||||||
tuple of the outer table is compared against every tuple of the inner table to
|
tuple of the outer table is compared against every tuple of the inner table to
|
||||||
find all pairs of tuples which satisfy the join condition. This method is
|
find all pairs of tuples which satisfy the join condition. This method is simple
|
||||||
simple but can be inefficient for large datasets due to its high computational
|
but can be inefficient for large datasets due to its high computational cost.
|
||||||
cost.
|
|
||||||
|
|
||||||
```python
|
```
|
||||||
Simplified version (to get the idea)
|
Simplified version (to get the idea)
|
||||||
for each tuple tr in r: (for each tuple ts in s: test pair (tr, ts))
|
for each tuple tr in r: (for each tuple ts in s: test pair (tr, ts))
|
||||||
```
|
```
|
||||||
@ -96,51 +94,48 @@ seek per block, leading to a total of $2 ∗b_r$ seeks.
|
|||||||
|
|
||||||
== Block-nested join
|
== Block-nested join
|
||||||
|
|
||||||
*Block Nested Loop Join*: A block nested loop join is an optimized version of the
|
*Block Nested Loop Join*: A block nested loop join is an optimized version of
|
||||||
nested loop join that reads and holds a block of rows from the outer table in
|
the nested loop join that reads and holds a block of rows from the outer table
|
||||||
memory and then loops through the inner table, reducing the number of disk
|
in memory and then loops through the inner table, reducing the number of disk
|
||||||
accesses and improving performance over a standard nested loop join, especially
|
accesses and improving performance over a standard nested loop join, especially
|
||||||
when indices are not available.
|
when indices are not available.
|
||||||
|
|
||||||
|
```
|
||||||
```python
|
|
||||||
Simplified version (to get the idea)
|
Simplified version (to get the idea)
|
||||||
for each block Br of r: for each block Bs of s:
|
for each block Br of r: for each block Bs of s:
|
||||||
for each tuple tr in r: (for each tuple ts in s: test pair (tr, ts))
|
for each tuple tr in r: (for each tuple ts in s: test pair (tr, ts))
|
||||||
```
|
```
|
||||||
|
|
||||||
// TODO: Add seek information
|
// TODO: Add seek information
|
||||||
Block transfer cost: $b_r ∗ b_s + b_r$, $b_r$ -- blocks in relation $r$, same
|
Block transfer cost: $b_r dot b_s + b_r$, $b_r$ -- blocks in relation $r$, same
|
||||||
for $s$.
|
for $s$.
|
||||||
|
|
||||||
== Merge join
|
== Merge join
|
||||||
|
|
||||||
*Merge Join*: A merge join is a database join operation where both the outer
|
*Merge Join*: A merge join is a database join operation where both the outer and
|
||||||
and inner tables are first sorted on the join key, and then merged together by
|
inner tables are first sorted on the join key, and then merged together by
|
||||||
sequentially scanning through both tables to find matching pairs. This method
|
sequentially scanning through both tables to find matching pairs. This method is
|
||||||
is highly efficient when the tables are *already sorted* or can be *sorted
|
highly efficient when the tables are *already sorted* or can be *sorted
|
||||||
quickly*, minimizes random disk access. Merge-join method is efficient; the
|
quickly*, minimizes random disk access. Merge-join method is efficient; the
|
||||||
number of block transfers is equal to the sum of the number of blocks in both
|
number of block transfers is equal to the sum of the number of blocks in both
|
||||||
files, $b_r + b_s$.
|
files, $b_r + b_s$. Assuming that $b_b$ buffer blocks are allocated to each
|
||||||
Assuming that $bb$ buffer blocks are allocated to each relation, the number of disk
|
relation, the number of disk seeks required would be $ceil(b_r/b_b) + ceil(b_s/b_b)$ disk
|
||||||
seeks required would be $⌈b_r∕b_b⌉+ ⌈b_s∕b_b⌉$ disk seeks
|
seeks
|
||||||
|
|
||||||
+ Sort Both Tables: If not already sorted, the outer table and the inner table
|
+ Sort Both Tables: If not already sorted, the outer table and the inner table are
|
||||||
are sorted based on the join keys.
|
sorted based on the join keys.
|
||||||
+ Merge: Once both tables are sorted, the algorithm performs a merging
|
+ Merge: Once both tables are sorted, the algorithm performs a merging operation
|
||||||
operation similar to that used in merge sort:
|
similar to that used in merge sort:
|
||||||
+ Begin with the first record of each table.
|
+ Begin with the first record of each table.
|
||||||
+ Compare the join keys of the current records from both tables.
|
+ Compare the join keys of the current records from both tables.
|
||||||
+ If the keys match, join the records and move to the next record in both tables.
|
+ If the keys match, join the records and move to the next record in both tables.
|
||||||
+ If the join key of the outer table is smaller, move to the next record in
|
+ If the join key of the outer table is smaller, move to the next record in the
|
||||||
the outer table.
|
outer table.
|
||||||
+ If the join key of the inner table is smaller, move to the next record in
|
+ If the join key of the inner table is smaller, move to the next record in the
|
||||||
the inner table.
|
inner table.
|
||||||
+ Continue this process until all records in either table have been examined.
|
+ Continue this process until all records in either table have been examined.
|
||||||
+ Output the Joined Rows;
|
+ Output the Joined Rows;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
== Hash-join
|
== Hash-join
|
||||||
|
|
||||||
*Hash Join*: A hash join is a database join operation that builds an in-memory
|
*Hash Join*: A hash join is a database join operation that builds an in-memory
|
||||||
@ -148,68 +143,67 @@ hash table using the join key from the smaller, often called the build table,
|
|||||||
and then probes this hash table using the join key from the larger, or probe
|
and then probes this hash table using the join key from the larger, or probe
|
||||||
table, to find matching pairs. This technique is very efficient for *large
|
table, to find matching pairs. This technique is very efficient for *large
|
||||||
datasets* where *indexes are not present*, as it reduces the need for nested
|
datasets* where *indexes are not present*, as it reduces the need for nested
|
||||||
loops.
|
loops.
|
||||||
|
|
||||||
- $h$ is a hash function mapping JoinAttrs values to ${0, 1, … , n_h}$, where
|
- $h$ is a hash function mapping JoinAttrs values to ${0, 1, ... , n_h}$, where
|
||||||
JoinAttrs denotes the common attributes of r and s used in the natural join.
|
JoinAttrs denotes the common attributes of $r$ and $s$ used in the natural join.
|
||||||
- $r_0$, $r_1$, … , rnh denote partitions of r tuples, each initially empty.
|
- $r_0, r_1, ..., r_n_h$ denote partitions of $r$ tuples, each initially empty.
|
||||||
Each tuple $t_r in r$ is put in partition $r_i$, where $i = h(t_r [#[JoinAttrs]])$.
|
Each tuple $t_r in r$ is put in partition $r_i$, where $i = h(t_r ["JoinAttrs"])$.
|
||||||
- $s_0$, $s_1$, ..., $s_n_h$ denote partitions of s tuples, each initially empty.
|
- $s_0$, $s_1$, ..., $s_n_h$ denote partitions of s tuples, each initially empty.
|
||||||
Each tuple $t_s in s$ is put in partition $s_i$, where $i = h(t_s [#[JoinAttrs]])$.
|
Each tuple $t_s in s$ is put in partition $s_i$, where $i = h(t_s ["JoinAttrs"])$.
|
||||||
|
|
||||||
Cost of block transfers: $3(b_r + b_s) + 4 n_h$. The hash join thus requires
|
Cost of block transfers: $3(b_r + b_s) + 4 n_h$. The hash join thus requires
|
||||||
$2(⌈b_r∕b_b⌉+⌈b_s∕b_b⌉)+ 2n_h$ seeks.
|
$2(ceil(b_r/b_b) + ceil(b_s/b_b))+ 2n_h$ seeks.
|
||||||
|
|
||||||
$b_b$ blocks are allocated for the input buffer and each output buffer.
|
$b_b$ blocks are allocated for the input buffer and each output buffer.
|
||||||
|
|
||||||
+ Build Phase:
|
+ Build Phase:
|
||||||
+ Choose the smaller table (to minimize memory usage) as the "build table."
|
+ Choose the smaller table (to minimize memory usage) as the "build table."
|
||||||
+ Create an in-memory hash table. For each record in the build table,
|
+ Create an in-memory hash table. For each record in the build table, compute a
|
||||||
compute a hash on the join key and insert the record into the hash table
|
hash on the join key and insert the record into the hash table using this hash
|
||||||
using this hash value as an index.
|
value as an index.
|
||||||
+ Probe Phase:
|
+ Probe Phase:
|
||||||
+ Take each record from the larger table, which is often referred to as the
|
+ Take each record from the larger table, which is often referred to as the
|
||||||
"probe table."
|
"probe table."
|
||||||
+ Compute the hash on the join key (same hash function used in the build
|
+ Compute the hash on the join key (same hash function used in the build phase).
|
||||||
phase).
|
+ Use this hash value to look up in the hash table built from the smaller table.
|
||||||
+ Use this hash value to look up in the hash table built from the smaller
|
+ If the bucket (determined by the hash) contains any entries, check each entry to
|
||||||
table.
|
see if the join key actually matches the join key of the record from the probe
|
||||||
+ If the bucket (determined by the hash) contains any entries, check each
|
table (since hash functions can lead to collisions).
|
||||||
entry to see if the join key actually matches the join key of the record
|
|
||||||
from the probe table (since hash functions can lead to collisions).
|
|
||||||
+ Output the Joined Rows.
|
+ Output the Joined Rows.
|
||||||
|
|
||||||
|
|
||||||
= Relational-algebra
|
= Relational-algebra
|
||||||
|
|
||||||
== Equivalence rules
|
== Equivalence rules
|
||||||
|
|
||||||
|
+ $ sigma_(theta_1 and theta_2)(E) = sigma_theta_1(sigma_theta_2(E)) $
|
||||||
|
+ $ sigma_theta_1(sigma_theta_2(E)) = sigma_theta_2(sigma_theta_1(E)) $
|
||||||
|
+ $ Pi_L_1(Pi_L_2(...(Pi_L_n (E))...)) = Pi_L_1(E) $ -- only the last one matters.
|
||||||
|
+ Selections can be combined with Cartesian products and theta joins:
|
||||||
|
$ sigma_theta (E_1 times E_2) = E_1 join_theta E_2 $
|
||||||
|
$ sigma_theta_1 (E_1 join_theta_2 E_2) = E_1 join_theta_1 and theta_2 E_2 $
|
||||||
|
+ $ E_1 join_theta E_2 = E_2 join_theta E_1 $
|
||||||
|
+ Join associativity: $ (E_1 join E_2) join E_3 = E_1 join (E_2 join E_3) $
|
||||||
|
$ (E_1 join_theta_1 E_2) join_(theta_2 and theta_3) E_3 = E_1 join_(theta_1 and theta_3) (E_2 join_theta_2 E_3) $
|
||||||
|
+ Selection distribution:
|
||||||
|
$ sigma_theta_1 (E_1 join_theta E_2) = (sigma_theta_0(E_1)) join_theta E_2 $
|
||||||
|
$ sigma_(theta_1 and theta_2)(E_1 join_theta E_2) = (sigma_theta_1 (E)1)) join_theta (sigma_theta_2 (E_2)) $
|
||||||
|
+ Projection distribution:
|
||||||
|
$ Pi_(L_1 union L_2) (E_1 join_theta E_2) = (Pi_L_1 (E_1) join_theta (Pi_L_2 (E_2))) $
|
||||||
|
$ Pi_(L_1 union L_2) (E_1 join_theta E_2) = Pi_(L_1 union L_2) ((Pi_(L_1 union L_3) (E_1)) join_theta (Pi_(L_2 union L_4) (E_2))) $
|
||||||
|
+ Union and intersection commmutativity:
|
||||||
|
$ E_1 union E_2 = E_2 union E_1 $
|
||||||
|
$ E_1 sect E_2 = E_2 sect E_1 $
|
||||||
|
+ Set union and intersection are associative:
|
||||||
|
$ (E_1 union E_2) union E_3 = E_1 union (E_2 union E_3) $
|
||||||
|
$ (E_1 sect E_2) sect E_3 = E_1 sect (E_2 sect E_3) $
|
||||||
|
+ The selection operation distributes over the union, intersection, and
|
||||||
|
set-difference operations:
|
||||||
|
$ sigma_P (E_1 - E_2) = sigma_P(E_1) - E_2 = sigma_P(E_1) - sigma_P(E_2) $
|
||||||
|
+ The projection operation distributes over the union operation:
|
||||||
|
$ Pi_L (E_1 union E_2) = (Pi_L(E_1)) union (Pi_L(E_2)) $
|
||||||
|
|
||||||
// FROM Database concepts
|
// FROM Database concepts
|
||||||
+ $σ_(θ_1∧θ_2)(E) ≡σ_(θ_1) (σ_(θ_2)(E))$
|
|
||||||
+ $σ_(θ_1)(σ_(θ_2)(E)) ≡σ_(θ_2)(σ_(θ_1)(E))$
|
|
||||||
+ $Π_(L_1)(Π_(L_2)(… (Π_(L_n)(E)) …)) ≡Π_(L_1)(E)$ -- only the last one matters.
|
|
||||||
+ Selections can be combined with Cartesian products and theta joins: $σ_θ(E_1
|
|
||||||
× E_2) ≡E_1 ⋈_θ E_2$ - This expression is just the definition of the theta
|
|
||||||
join |||| $σ_(θ_1)(E_1 ⋈_(θ_2) E_2) ≡E_1 ⋈_(θ_1) ∧ θ_2 E_2$
|
|
||||||
+ $E_1 ⋈_θ E_2 ≡E_2 ⋈_θ E_1$
|
|
||||||
+ Join associativity: $(E_1 ⋈ E_2) ⋈ E_3 ≡E_1 ⋈(E_2 ⋈E_3)$ |||| $(E_1 join_theta_1
|
|
||||||
E_2) join_(theta_2 and theta_3) |||| E_3 ≡E_1 join_(theta_1 or theta_3) (E_2
|
|
||||||
join_theta_2 E_3)$
|
|
||||||
+ Selection distribution: $σ_(θ_1)(E_1 ⋈_θ E_2) ≡(σ_(θ_1) (E_1)) ⋈_θ E_2$;
|
|
||||||
$σ_(θ_1∧θ_2)(E_1 ⋈_θ E_2) ≡ (σ_(θ_1)(E_1)) ⋈_θ (σ_(θ_2)(E_2))$
|
|
||||||
+ Projection distribution: - $Π_(L_1∪L_2) (E_1 ⋈_θ E_2) ≡(Π_(L_1(E_1)) ⋈_θ
|
|
||||||
(Π_(L_2)(E_2))$ |||| $Π(L_1∪L_2) (E_1 ⋈_θ E_2) ≡Π_(L_1∪L_2) ((Π_(L_1∪L_3) (E_1))
|
|
||||||
⋈_θ (Π_(L_2∪L_4) (E_2)))$
|
|
||||||
+ Union and intersection commmutativity: $E_1 ∪E_2 ≡E_2 ∪E_1 |||| - E_1 ∩E_2 ≡E_2 ∩E_1$
|
|
||||||
+ Set union and intersection are associative: $(E_1 ∪E_2) ∪E_3 ≡E_1 ∪(E_2 ∪E_3) |||| (E_1
|
|
||||||
∩E_2) ∩E_3 ≡E_1 ∩(E_2 ∩E_3)$;
|
|
||||||
+ The selection operation distributes over the union, intersection, and
|
|
||||||
set-difference operations: $σ_θ(E_1 ∪E_2) ≡σ_θ(E_1) ∪σ_θ(E_2) |||| σ_θ(E_1 ∩E_2) ≡σ_θ(E_1)
|
|
||||||
∩σ_θ(E_2) |||| σ_θ(E_1 −E_2) ≡σ_θ(E_1) −σ_θ(E_2) |||| σ_θ(E_1 ∩E_2) ≡σ_θ(E_1) ∩E_2 |||| σ_θ(E_1 −E_2) ≡σ_θ(E_1)
|
|
||||||
−E_2$;
|
|
||||||
+ The projection operation distributes over the union operation - $Π_L(E_1
|
|
||||||
∪E_2) ≡(Π_L_(E_1)) ∪(Π_L(E_2))$.
|
|
||||||
|
|
||||||
// == Operations
|
// == Operations
|
||||||
//
|
//
|
||||||
@ -243,17 +237,17 @@ $b_b$ blocks are allocated for the input buffer and each output buffer.
|
|||||||
// Right Outer Join: $R join.r S$. Purpose: Extends join to include non-matching
|
// Right Outer Join: $R join.r S$. Purpose: Extends join to include non-matching
|
||||||
// tuples from one or both relations, filling with nulls.
|
// tuples from one or both relations, filling with nulls.
|
||||||
|
|
||||||
|
= Concurrency
|
||||||
= Concurrency
|
|
||||||
|
|
||||||
|
|
||||||
=== Conflict
|
=== Conflict
|
||||||
|
|
||||||
We say that I and J conflict if they are operations by *different transactions* on the
|
We say that $I$ and $J$ conflict if they are operations by *different
|
||||||
*same data item*, and at least one of these instructions is a *write* operation.
|
transactions* on the *same data item*, and at least one of these instructions is
|
||||||
For example: I = read(Q), J = read(Q) -- Not a conflict; I = read(Q), J =
|
a *write* operation. For example:
|
||||||
write(Q) -- Conflict; I = write(Q), J = read(Q) -- Conflict; I = write(Q), J =
|
- $I = #[`read(Q)`]$ , $J = #[`read(Q)`]$ -- Not a conflict;
|
||||||
write(Q) -- Conflict.
|
- $I = #[`read(Q)`]$ , $J = #[`write(Q)`]$ -- Conflict;
|
||||||
|
- $I = #[`write(Q)`]$, $J = #[`read(Q)`]$ -- Conflict;
|
||||||
|
- $I = #[`write(Q)`]$, $J = #[`write(Q)`]$ -- Conflict.
|
||||||
|
|
||||||
// + I = read(Q), J = read(Q). The order of I and J *does not matter*, since the same
|
// + I = read(Q), J = read(Q). The order of I and J *does not matter*, since the same
|
||||||
// value of Q is read by $T_i$ and $T _j$, regardless of the order.
|
// value of Q is read by $T_i$ and $T _j$, regardless of the order.
|
||||||
@ -280,33 +274,35 @@ equivalent*. We can swap only _adjacent_ operations.
|
|||||||
|
|
||||||
The concept of conflict equivalence leads to the concept of conflict
|
The concept of conflict equivalence leads to the concept of conflict
|
||||||
serializability. We say that a schedule $S$ is *conflict serializable* if it is
|
serializability. We say that a schedule $S$ is *conflict serializable* if it is
|
||||||
conflict equivalent to a serial schedule.
|
conflict equivalent to a serial schedule.
|
||||||
|
|
||||||
// TODO: rename to precedence
|
// TODO: rename to precedence
|
||||||
=== Precedence graph
|
=== Precedence graph
|
||||||
|
|
||||||
Simple and efficient method for determining the conflict
|
Simple and efficient method for determining the conflict seriazability of a
|
||||||
seriazability of a schedule. Consider a schedule $S$. We construct a directed
|
schedule. Consider a schedule $S$. We construct a directed graph, called a
|
||||||
graph, called a precedence graph, from $S$. The set of vertices
|
precedence graph, from $S$. The set of vertices consists of all the transactions
|
||||||
consists of all the transactions participating in the schedule. The set of
|
participating in the schedule. The set of edges consists of all edges $T_i arrow T_j$ for
|
||||||
edges consists of all edges $T_i arrow T_j$ for which one of three conditions holds:
|
which one of three conditions holds:
|
||||||
|
|
||||||
+ $T_i$ executes `write(Q)` before $T_j$ executes `read(Q)`.
|
+ $T_i$ executes `write(Q)` before $T_j$ executes `read(Q)`.
|
||||||
+ $T_i$ executes `read(Q)` before $T_j$ executes `write(Q)`.
|
+ $T_i$ executes `read(Q)` before $T_j$ executes `write(Q)`.
|
||||||
+ $T_i$ executes `write(Q)` before $T_j$ executes `write(Q)`.
|
+ $T_i$ executes `write(Q)` before $T_j$ executes `write(Q)`.
|
||||||
|
|
||||||
If the precedence graph for $S$ has a cycle, then schedule $S$ is not conflict
|
If the precedence graph for $S$ has a cycle, then schedule $S$ is not conflict
|
||||||
serializable. If the graph contains no cycles, then the schedule $S$ is
|
serializable. If the graph contains no cycles, then the schedule $S$ is conflict
|
||||||
conflict serializable.
|
serializable.
|
||||||
|
|
||||||
== Standard isolation levels
|
== Standard isolation levels
|
||||||
|
|
||||||
- *Serializable* usually ensures serializable execution.
|
- *Serializable* usually ensures serializable execution.
|
||||||
- *Repeatable* read allows only committed data to be read and further requires that,
|
- *Repeatable* read allows only committed data to be read and further requires
|
||||||
between two reads of a data item by a transaction, no other transaction is allowed
|
that, between two reads of a data item by a transaction, no other transaction is
|
||||||
to update it. However, the transaction may not be serializable
|
allowed to update it. However, the transaction may not be serializable
|
||||||
- *Read committed* allows only committed data to be read, but does not require re- peatable reads.
|
- *Read committed* allows only committed data to be read, but does not require re-
|
||||||
- *Read uncommitted* allows uncommitted data to be read. Lowest isolation level allowed by SQL.
|
peatable reads.
|
||||||
|
- *Read uncommitted* allows uncommitted data to be read. Lowest isolation level
|
||||||
|
allowed by SQL.
|
||||||
|
|
||||||
== Protocols
|
== Protocols
|
||||||
|
|
||||||
@ -326,50 +322,51 @@ Every cascadeless schedule is also recoverable.
|
|||||||
|
|
||||||
=== Lock-based
|
=== Lock-based
|
||||||
|
|
||||||
*Shared Lock* -- If a transaction $T_i$ has obtained a shared-mode lock (denoted by $S$) on
|
*Shared Lock* -- If a transaction $T_i$ has obtained a shared-mode lock (denoted
|
||||||
item Q, then Ti can read, but cannot write, $Q$. \
|
by $S$) on item Q, then Ti can read, but cannot write, $Q$.
|
||||||
|
|
||||||
*Exclusive Lock* -- If a transaction $T_i$ has obtained an exclusive-mode lock
|
*Exclusive Lock* -- If a transaction $T_i$ has obtained an exclusive-mode lock
|
||||||
(denoted by $X$) on item Q, then Ti can both read and write $Q$.
|
(denoted by $X$) on item Q, then Ti can both read and write $Q$.
|
||||||
|
|
||||||
|
|
||||||
==== 2-phased lock protocol
|
==== 2-phased lock protocol
|
||||||
|
|
||||||
*The Two-Phase Locking (2PL)* Protocol is a concurrency control method used in
|
*The Two-Phase Locking (2PL)* Protocol is a concurrency control method used in
|
||||||
database systems to ensure serializability of transactions. The protocol
|
database systems to ensure serializability of transactions. The protocol
|
||||||
involves two distinct phases: *Locking Phase (Growing Phase):* A transaction
|
involves two distinct phases: *Locking Phase (Growing Phase):* A transaction may
|
||||||
may acquire locks but cannot release any locks. During this phase, the
|
acquire locks but cannot release any locks. During this phase, the transaction
|
||||||
transaction continues to lock all the resources (data items) it needs to
|
continues to lock all the resources (data items) it needs to execute.
|
||||||
execute. \ *Unlocking Phase (Shrinking Phase):* The transaction releases locks
|
|
||||||
and cannot acquire any new ones. Once a transaction starts releasing locks, it
|
|
||||||
moves into this phase until all locks are released.
|
|
||||||
|
|
||||||
==== Problems of locks
|
*Unlocking Phase (Shrinking Phase):* The transaction releases locks and cannot
|
||||||
|
acquire any new ones. Once a transaction starts releasing locks, it moves into
|
||||||
|
this phase until all locks are released.
|
||||||
|
|
||||||
*Deadlock* is a condition where two or more tasks are each waiting for the
|
==== Problems of locks
|
||||||
other to release a resource, or more than two tasks are waiting for resources
|
|
||||||
in a circular chain.
|
*Deadlock* is a condition where two or more tasks are each waiting for the other
|
||||||
\ *Starvation* (also known as indefinite blocking) occurs
|
to release a resource, or more than two tasks are waiting for resources in a
|
||||||
when a process or thread is perpetually denied necessary resources to process
|
circular chain.
|
||||||
its work. Unlike deadlock, where everything halts, starvation only affects some
|
|
||||||
while others progress.
|
*Starvation* (also known as indefinite blocking) occurs when a process or thread
|
||||||
|
is perpetually denied necessary resources to process its work. Unlike deadlock,
|
||||||
|
where everything halts, starvation only affects some while others progress.
|
||||||
|
|
||||||
=== Timestamp-based
|
=== Timestamp-based
|
||||||
|
|
||||||
*Timestamp Assignment:* Each transaction is given a unique timestamp when it
|
*Timestamp Assignment:* Each transaction is given a unique timestamp when it
|
||||||
starts. This timestamp determines the transaction's temporal order relative to
|
starts. This timestamp determines the transaction's temporal order relative to
|
||||||
others. *Read Rule:* A transaction can read an object if the last write
|
others. *Read Rule:* A transaction can read an object if the last write occurred
|
||||||
occurred by a transaction with an earlier or the same timestamp. *Write Rule:*
|
by a transaction with an earlier or the same timestamp. *Write Rule:* A
|
||||||
A transaction can write to an object if the last read and the last write
|
transaction can write to an object if the last read and the last write occurred
|
||||||
occurred by transactions with earlier or the same timestamps.
|
by transactions with earlier or the same timestamps.
|
||||||
|
|
||||||
=== Validation-based
|
=== Validation-based
|
||||||
|
|
||||||
Assumes that conflicts are rare and checks for them only at the end of a transaction.
|
Assumes that conflicts are rare and checks for them only at the end of a
|
||||||
*Working Phase:* Transactions execute without acquiring locks, recording all
|
transaction. *Working Phase:* Transactions execute without acquiring locks,
|
||||||
data reads and writes. *Validation Phase:* Before committing, each transaction
|
recording all data reads and writes. *Validation Phase:* Before committing, each
|
||||||
must validate that no other transactions have modified the data it accessed.
|
transaction must validate that no other transactions have modified the data it
|
||||||
*Commit Phase:* If the validation is successful, the transaction commits and
|
accessed. *Commit Phase:* If the validation is successful, the transaction
|
||||||
applies its changes. If not, it rolls back and may be restarted.
|
commits and applies its changes. If not, it rolls back and may be restarted.
|
||||||
|
|
||||||
// === Version isolation
|
// === Version isolation
|
||||||
|
|
||||||
@ -388,39 +385,42 @@ In the *redo phase*, the system replays updates of all transactions by scanning
|
|||||||
the log forward from the last checkpoint. The specific steps taken while
|
the log forward from the last checkpoint. The specific steps taken while
|
||||||
scanning the log are as follows:
|
scanning the log are as follows:
|
||||||
|
|
||||||
+ The list of transactions to be rolled back, undo-list, is initially set to the list
|
+ The list of transactions to be rolled back, undo-list, is initially set to the
|
||||||
$L$ in the $<#[checkpoint] L>$ log record.
|
list
|
||||||
+ Whenever a normal log record of the form $<T_i, X_j, V_1, V_2>$, or a redo-
|
$L$ in the $<#[checkpoint] L>$ log record.
|
||||||
only log record of the form $<T_i, X_j, V_2>$ is encountered, the operation is
|
+ Whenever a normal log record of the form $<T_i, X_j, V_1, V_2>$, or a redo- only
|
||||||
|
log record of the form $<T_i, X_j, V_2>$ is encountered, the operation is
|
||||||
redone; that is, the value $V_2$ is written to data item $X_j$.
|
redone; that is, the value $V_2$ is written to data item $X_j$.
|
||||||
+ Whenever a log record of the form $<T_i #[start]>$ is found, $T_i$ is added to
|
+ Whenever a log record of the form $<T_i #[start]>$ is found, $T_i$ is added to
|
||||||
undo-list.
|
undo-list.
|
||||||
+ Whenever a log record of the form $<T_i #[abort]>$ or $<T_i #[commit]>$ is found,
|
+ Whenever a log record of the form $<T_i #[abort]>$ or $<T_i #[commit]>$ is
|
||||||
|
found,
|
||||||
$T_i$ is removed from undo-list.
|
$T_i$ is removed from undo-list.
|
||||||
|
|
||||||
At the end of the redo phase, undo-list contains the list of all transactions that
|
At the end of the redo phase, undo-list contains the list of all transactions
|
||||||
are incomplete, that is, they neither committed nor completed rollback before the crash.
|
that are incomplete, that is, they neither committed nor completed rollback
|
||||||
\ In the *undo phase*, the system rolls back all transactions in the undo-list.
|
before the crash.
|
||||||
It performs rollback by scanning the log backward from the end:
|
|
||||||
|
In the *undo phase*, the system rolls back all transactions in the undo-list. It
|
||||||
|
performs rollback by scanning the log backward from the end:
|
||||||
|
|
||||||
+ Whenever it finds a log record belonging to a transaction in the undo-list, it
|
+ Whenever it finds a log record belonging to a transaction in the undo-list, it
|
||||||
performs undo actions just as if the log record had been found during the
|
performs undo actions just as if the log record had been found during the
|
||||||
rollback of a failed transaction.
|
rollback of a failed transaction.
|
||||||
+ When the system finds a $<T_i #[start]>$ log record for a transaction $T_i$ in undo-
|
+ When the system finds a $<T_i #[start]>$ log record for a transaction $T_i$ in
|
||||||
list, it writes a $<T_i #[abort]>$ log record to the log and removes $T_i$ from undo-
|
undo- list, it writes a $<T_i #[abort]>$ log record to the log and removes $T_i$ from
|
||||||
list.
|
undo- list.
|
||||||
+ The undo phase terminates once undo-list becomes empty, that is, the system
|
+ The undo phase terminates once undo-list becomes empty, that is, the system has
|
||||||
has found $<T_i #[start]>$ log records for all transactions that were initially
|
found $<T_i #[start]>$ log records for all transactions that were initially in
|
||||||
in undo-list.
|
undo-list.
|
||||||
|
|
||||||
== Log types
|
== Log types
|
||||||
|
|
||||||
- $<T_i, X_j, V_1, V_2>$ -- an update log record, indicating that transaction
|
- $<T_i, X_j, V_1, V_2>$ -- an update log record, indicating that transaction
|
||||||
$T_i$ has performed a write on data item $X_j$. $X_j$ had value $V_1$ before
|
$T_i$ has performed a write on data item $X_j$. $X_j$ had value $V_1$ before the
|
||||||
the write and has value $V_2$ after the write;
|
write and has value $V_2$ after the write;
|
||||||
- $<T_i #[start]>$ -- $T_i$ has started;
|
- $<T_i #[start]>$ -- $T_i$ has started;
|
||||||
- $<T_i #[commit]>$ -- $T_i$ has committed;
|
- $<T_i #[commit]>$ -- $T_i$ has committed;
|
||||||
- $<T_i #[abort]>$ -- $T_i$ has aborted;
|
- $<T_i #[abort]>$ -- $T_i$ has aborted;
|
||||||
- $<#[checkpoint] {T_0, T_1, dots, T_n}>$ -- a checkpoint with a list of active
|
- $<#[checkpoint] {T_0, T_1, dots, T_n}>$ -- a checkpoint with a list of active
|
||||||
transactions at the moment of checkpoint.
|
transactions at the moment of checkpoint.
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user