<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>database on liang2kl's Blog</title><link>https://yeshe.ng/blog/tags/database/</link><description>Recent content in database on liang2kl's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><managingEditor>liang2kl@outlook.com (Liang Yesheng)</managingEditor><webMaster>liang2kl@outlook.com (Liang Yesheng)</webMaster><copyright>from 2021, to infinity and beyond...</copyright><lastBuildDate>Thu, 05 May 2022 23:11:19 +0800</lastBuildDate><atom:link href="https://yeshe.ng/blog/tags/database/index.xml" rel="self" type="application/rss+xml"/><item><title>Read Phenomena and Isolation Levels</title><link>https://yeshe.ng/blog/posts/2022/05/isolation/</link><pubDate>Thu, 05 May 2022 23:11:19 +0800</pubDate><author>liang2kl@outlook.com (Liang Yesheng)</author><guid>https://yeshe.ng/blog/posts/2022/05/isolation/</guid><description>In database systems, isolation determines how transaction integrity is visible to other users and systems.</description><content>&lt;p>Reference: &lt;a href="https://en.wikipedia.org/wiki/Isolation_(database_systems)">https://en.wikipedia.org/wiki/Isolation_(database_systems)&lt;/a>&lt;/p>
&lt;p>Isolation is typically defined at database level as a property that defines how or when the changes made by one operation become visible to others.&lt;/p>
&lt;h2 id="read-phenomena">Read phenomena&lt;/h2>
&lt;h3 id="dirty-reads">Dirty reads&lt;/h3>
&lt;p>A dirty read (aka uncommitted dependency) occurs when a transaction is allowed to read data from a row that has been modified by another running transaction and &lt;em>not yet committed&lt;/em>.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/05/dirty-read.webp" alt="">&lt;/p>
&lt;h3 id="non-repetable-reads">Non-repetable reads&lt;/h3>
&lt;p>A non-repeatable read occurs when, during the course of a transaction, a row is &lt;em>retrieved twice&lt;/em> and the values within the row &lt;em>differ&lt;/em> between reads.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/05/non-repeatable-read.webp" alt="">&lt;/p>
&lt;h3 id="phantom-reads">Phantom reads&lt;/h3>
&lt;p>A phantom read occurs when, in the course of a transaction, &lt;em>new rows are added or removed&lt;/em> by another transaction to the records being read.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/05/phantom-read.webp" alt="">&lt;/p>
&lt;h2 id="isolation-levels">Isolation levels&lt;/h2>
&lt;blockquote>
&lt;p>Of the four ACID properties in a DBMS (Database Management System), the isolation property is the one most often relaxed.&lt;/p>
&lt;p>For many database applications, the majority of database transactions can be constructed to avoid requiring high isolation levels (e.g. SERIALIZABLE level), thus reducing the locking overhead for the system.&lt;/p>
&lt;/blockquote>
&lt;h3 id="serializable">Serializable&lt;/h3>
&lt;p>The execution of concurrent SQL-transactions at isolation level SERIALIZABLE is guaranteed to be serializable.&lt;/p>
&lt;p>When using non-lock based concurrency control&amp;hellip; And also range-locks must be acquired when a SELECT query uses a ranged WHERE clause, especially to avoid the phantom reads phenomenon.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Snapshot isolation&lt;/strong>&lt;/p>
&lt;p>snapshot isolation is a guarantee that all reads made in a transaction will see a consistent snapshot of the database (in practice it reads the last committed values that existed at the time it started), and the transaction itself will successfully commit only if no updates it has made conflict with any concurrent updates made since that snapshot.&lt;/p>
&lt;/blockquote>
&lt;h3 id="repeatable-reads">Repeatable reads&lt;/h3>
&lt;p>Range-locks are not managed, so &lt;em>phantom reads&lt;/em> can occur.&lt;/p>
&lt;h3 id="read-committed">Read committed&lt;/h3>
&lt;p>Read locks are released as soon as the SELECT operation is performed, so the &lt;em>non-repeatable reads&lt;/em> phenomenon can occur in this isolation level.&lt;/p>
&lt;h3 id="read-uncommitted">Read uncommitted&lt;/h3>
&lt;p>No read locks. Dirty reads are allowed, so one transaction may see not-yet-committed changes made by other transactions.&lt;/p></content></item><item><title>Concurrency Control for Database Transactions</title><link>https://yeshe.ng/blog/posts/2022/04/database/</link><pubDate>Mon, 11 Apr 2022 23:27:56 +0800</pubDate><author>liang2kl@outlook.com (Liang Yesheng)</author><guid>https://yeshe.ng/blog/posts/2022/04/database/</guid><description>DATABASE SYSTEMS: The Complete Book</description><content>&lt;p>来自 &lt;em>DATABASE SYSTEMS: The Complete Book&lt;/em>&lt;/p>
&lt;h2 id="serial-and-serializable-schedules">Serial and Serializable Schedules&lt;/h2>
&lt;p>&lt;strong>Serial schedule&lt;/strong>: no mixing of actions from different transactions.&lt;/p>
&lt;p>&lt;strong>Serializable schedule&lt;/strong>: if there is a &lt;em>serial&lt;/em> schedule S&amp;rsquo; such that for
every initial database state, the &lt;em>effects&lt;/em> of S and S&amp;rsquo; are the same.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/serializable.webp" alt="">&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/nonserializable.webp" alt="">&lt;/p>
&lt;p>The details of the transactions do matter, but it is not realistic for the
scheduler to concern itself with the details of computation undertaken by
transactions.&lt;/p>
&lt;p>We only care about the reads $r_T(X)$ and writes $w_T(X)$ performed by the transaction $T$.&lt;/p>
&lt;h2 id="conflict-serializability">Conflict-Serializability&lt;/h2>
&lt;p>Actions that conflict (i.e. their order may not be swapped):&lt;/p>
&lt;ol>
&lt;li>Two actions of the same transaction.&lt;/li>
&lt;li>Two writes of the same database element by different transactions.&lt;/li>
&lt;li>A read and a write of the same database element by different transactions.&lt;/li>
&lt;/ol>
&lt;p>In other words, for actions from &lt;em>different&lt;/em> transactions, they conflict when:&lt;/p>
&lt;ol>
&lt;li>They involve the same database element, and&lt;/li>
&lt;li>At least one is a write.&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>Conflict-equivalent&lt;/strong>: two schedules can be turned one into the other by
a sequence of nonconflicting swaps of adjacent actions.&lt;/p>
&lt;p>&lt;strong>Conflict-serializable&lt;/strong>: the schedule is conflict-equivalent to a &lt;em>serial&lt;/em> schedule&lt;/p>
&lt;p>conflict-serializability $\Rightarrow$ serializability&lt;/p>
&lt;p>&lt;strong>Precedence&lt;/strong>: if there are actions $A_1$ of $T_1$ and $A_2$ of $T_2$, such that:&lt;/p>
&lt;ul>
&lt;li>$A_1$ is ahead of $A_2$ in the schedule $S$,&lt;/li>
&lt;li>Both $A_1$ and $A_2$ involve the same database element, and&lt;/li>
&lt;li>At least one of $A_1$ and $A_2$ is a write action.&lt;/li>
&lt;/ul>
&lt;p>then we say that $T_1$ takes precedence over $T_2$ in $S$ ($T_1&amp;lt;_ST_2$).&lt;/p>
&lt;p>Any conflict-equivalent serial schedule must have $T_1$ before $T_2$.&lt;/p>
&lt;p>If the precedence graph is acyclic, then the schedule is conflict-equivalent.&lt;/p>
&lt;p>Proof: for $n$, arrange the schedule by (Actions of $T_i$)(Actions of the other $n-1$ transactions) where $T_i$ is one node without an in arc.&lt;/p>
&lt;h2 id="enforcing-serializability-by-locks">Enforcing Serializability by Locks&lt;/h2>
&lt;p>The use of lock:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Consistency of Transactions&lt;/strong>: Actions and locks must relate in the expected ways:
&lt;ol>
&lt;li>A transaction can only read or write an element if it previously was granted a lock on that element and hasn’t yet released the lock.&lt;/li>
&lt;li>If a transaction locks an element, it must later unlock that element.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>&lt;strong>Legality of Schedules&lt;/strong>: Locks must have their intended meaning: no two transactions may have locked the same element without one having first released the lock.&lt;/li>
&lt;/ul>
&lt;p>The &lt;strong>two-phase locking&lt;/strong> condition than can ensure conflict-serializability:&lt;/p>
&lt;ul>
&lt;li>In every transaction, all lock actions precede all unlock actions.&lt;/li>
&lt;/ul>
&lt;p>A transaction that obeys the 2PL condition is said to be a &lt;strong>two-phase-locked transaction&lt;/strong>, or &lt;strong>2PL transaction&lt;/strong>.&lt;/p>
&lt;p>Proof: for $n$, arrange the schedule by (Actions of $T_i$)(Actions of the other $n-1$ transactions) where $T_i$ is the transaction with the first &lt;em>unlock&lt;/em> action $u_iX$.&lt;/p>
&lt;p>The risk of deadlock:&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/deadlock.webp" alt="">&lt;/p>
&lt;h2 id="locking-systems-with-several-lock-modes">Locking Systems With Several Lock Modes&lt;/h2>
&lt;p>Lock modes:&lt;/p>
&lt;ul>
&lt;li>shared&lt;/li>
&lt;li>exclusive&lt;/li>
&lt;/ul>
&lt;p>The compatibility matrix:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">&lt;/th>
&lt;th style="text-align:center">Request S&lt;/th>
&lt;th style="text-align:center">Request X&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">Currently S&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">Currently X&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The deadlock problem caused by upgrading locks:&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/upgrading-deadlock.webp" alt="">&lt;/p>
&lt;p>Avoid the problem with a third lock mode: &lt;strong>update locks&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>An update lock $ul_i(X)$ gives transaction $T_j$ only the privilege to read X, not to write X;&lt;/li>
&lt;li>Only the update lock can be upgraded to a write lock later; a read lock cannot be upgraded.&lt;/li>
&lt;/ul>
&lt;p>The compatibility matrix:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">&lt;/th>
&lt;th style="text-align:center">Request S&lt;/th>
&lt;th style="text-align:center">Request X&lt;/th>
&lt;th style="text-align:center">Request U&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">Currently S&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">Currently X&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">Currently U&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The columns for U and S locks are the same, and the rows for U and X locks are the same.&lt;/p>
&lt;p>And now:&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/upgrading-updatelock.webp" alt="">&lt;/p>
&lt;h2 id="an-architecture-for-a-locking-scheduler">An Architecture for a Locking Scheduler&lt;/h2>
&lt;p>The architecture discussed here: the scheduler insert and release locks.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/scheduler-insert-lock.webp" alt="">&lt;/p>
&lt;ol>
&lt;li>Part 1: inserts appropriate lock actions ahead of all database-access operations&lt;/li>
&lt;li>Part 2: for received action,
&lt;ol>
&lt;li>if the issuing transcation is already delayed, then delay this action&lt;/li>
&lt;li>otherwise,
&lt;ol>
&lt;li>if the action is db access (&lt;em>the required locks are already been granted&lt;/em>), execute it&lt;/li>
&lt;li>if is lock action
&lt;ol>
&lt;li>if the lock can be granted: modify the lock table&lt;/li>
&lt;li>otherwise, request the lock and delay&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>When a transcation commits or aborts, Part 1 releases all locks held by the transaction; if any transactions are waiting for any of these locks, notify Part 2&lt;/li>
&lt;li>Part 2 checks which actions can be executed now&lt;/li>
&lt;/ol>
&lt;p>The lock table entry:&lt;/p>
&lt;ol>
&lt;li>The &lt;em>group mode&lt;/em>: the most stringent conditions&lt;/li>
&lt;li>The &lt;em>waiting bit&lt;/em>: at least one transaction is waiting&lt;/li>
&lt;li>A list of transactions that hold or waiting for the lock&lt;/li>
&lt;/ol>
&lt;h2 id="hierarchies-of-database-elements">Hierarchies of Database Elements&lt;/h2>
&lt;p>&lt;strong>Warning locks&lt;/strong>: useful for hierarchical structure.&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th style="text-align:center">&lt;/th>
&lt;th style="text-align:center">IS&lt;/th>
&lt;th style="text-align:center">IX&lt;/th>
&lt;th style="text-align:center">S&lt;/th>
&lt;th style="text-align:center">X&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td style="text-align:center">IS&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">IX&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">S&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">Yes&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td style="text-align:center">X&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;td style="text-align:center">No&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The &lt;strong>phantom tuple&lt;/strong>: one that should have been locked but wasn’t, because it didn’t exist at the time the locks were taken.&lt;/p>
&lt;p>Solution: acquire an X lock on the entire relation.&lt;/p>
&lt;h2 id="the-tree-protocol">The Tree Protocol&lt;/h2>
&lt;p>The problem: only one transaction that is not read-only can access the B-tree at any time, because the root node must be locked (at least with an update lock).&lt;/p>
&lt;p>Solution: as soon as a transaction moves to a child of the root and observes the (quite usual) situation that rules out a rewrite of the root, we would like to release the lock on the root; but it violates 2PL, so a new protocol is needed.&lt;/p>
&lt;p>&lt;strong>The tree protocol&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>The schedule is legal (i.e. does not violate lock schemes).&lt;/li>
&lt;li>A transaction’s first lock may be at any node of the tree.&lt;/li>
&lt;li>Subsequent locks may only be acquired if the transaction currently has a lock on the parent node.&lt;/li>
&lt;li>Nodes may be unlocked at any time.&lt;/li>
&lt;li>A transaction may not relock a node on which it has released a lock, even if it still holds a lock on the node’s parent.&lt;/li>
&lt;/ol>
&lt;p>Conclusion: the precedence graph must always be acyclic if the tree protocol is obeyed. Proof:&lt;/p>
&lt;ul>
&lt;li>If two transactions lock several elements in common, then they are all locked in the same order.&lt;/li>
&lt;li>If $T_i$ locks the root before $T_j$, then $T_i$ locks every node in common with $T_j$ before $T_j$ does.&lt;/li>
&lt;/ul>
&lt;h2 id="concurrency-control-by-timestamps">Concurrency Control by Timestamps&lt;/h2>
&lt;p>Two approaches to generate timestamp:&lt;/p>
&lt;ol>
&lt;li>use the system clock&lt;/li>
&lt;li>the scheduler maintaining a counter&lt;/li>
&lt;/ol>
&lt;p>For the database element $X$:&lt;/p>
&lt;ol>
&lt;li>$RT(X)$: the read time of $X$&lt;/li>
&lt;li>$WT(X)$: the write time of $X$&lt;/li>
&lt;li>$C(X)$: the commit bit fot $X$, true when the most recent transaction to write $X$ has already commited.&lt;/li>
&lt;/ol>
&lt;p>Two kinds of unrealizable behaviours:&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/read-too-late.webp" alt="">&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/write-too-late.webp" alt="">&lt;/p>
&lt;p>The problem with dirty data:&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/dirty-read.webp" alt="">&lt;/p>
&lt;p>$T$ better delays until $U$ commits.&lt;/p>
&lt;p>The commit bit will be false.&lt;/p>
&lt;p>The &lt;strong>Thomas write rule&lt;/strong>: the writes can be skipped when a write with a later write-time is already in place (read intention for value written by T is too-late, as the value is written by a logically latter transaction).&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/thomas-write-rule.webp" alt="">&lt;/p>
&lt;p>The scheduler, in response to a read or write request from a transaction T has the choice of:&lt;/p>
&lt;ul>
&lt;li>Granting the request,&lt;/li>
&lt;li>Aborting T and restarting T with a new timestamp&lt;/li>
&lt;li>Delaying T and later deciding whether to abort or grant the request.&lt;/li>
&lt;/ul>
&lt;p>The rules for timestamp-based scheduling:&lt;/p>
&lt;ol>
&lt;li>The scheduler receives a request $r_T(X)$.
&lt;ol>
&lt;li>$TS(T)\ge WT(X)$: physically realizable.
&lt;ol>
&lt;li>$C(X)$ is true: grant the request; set $RT(X)$ if $TS(T)&amp;gt;RT(X)$.&lt;/li>
&lt;li>$C(X)$ is false: delay until becomes true, or that transaction aborts (to avoid dirty reads).&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>$TS(T)&amp;lt;WT(X)$: physically unrealizable, rollback $T$.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>The scheduler receives a request $w_T(X)$.
&lt;ol>
&lt;li>$TS(T) \ge RT(X)$ and $TS(T) &amp;gt; WT(X)$: physically realizable and must be performed (?).
&lt;ol>
&lt;li>Write $X$,&lt;/li>
&lt;li>Set $WT(X) := TS(T)$, and&lt;/li>
&lt;li>Set $C(X) := \texttt{false}$.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>$TS(T) \ge RT(X)$ but $TS(T) &amp;lt; WT(X)$: physically realizable, and
&lt;ol>
&lt;li>If $C(X)$ is true, ignore the write by T (the thomas write rule);&lt;/li>
&lt;li>otherwise, delay T until the previous write operation commits or aborts.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>$TS(T) &amp;lt; RT(X)$: physically unrealizable, roll back T.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>The scheduler receives a request to &lt;em>commit T&lt;/em>: find all elements written by T, and set $C(X) := \texttt{true}$; the delayed transactions are allowed to proceed.&lt;/li>
&lt;li>The scheduler receives a request to &lt;em>abort T&lt;/em>, or to rollback: check all delaying transcation waiting for any element that T wrote to see if they can proceed.&lt;/li>
&lt;/ol>
&lt;p>The use of &lt;strong>multiversion timestamps&lt;/strong>: to provide an appropriate version for a read action (the version of X written immediately before T theoretically executed), even if the latest version is written after the transcation.&lt;/p>
&lt;p>Comparision of locking and timestamp schemes:&lt;/p>
&lt;p>Generally, timestamping is superior in situations where either most transactions are read-only, or it is rare that concurrent transactions will try to read and write the same element. In high-conflict situations, locking performs better.&lt;/p>
&lt;ul>
&lt;li>Locking will frequently delay transactions as they wait for locks.&lt;/li>
&lt;li>If concurrent transactions frequently read and write elements in common, then &lt;em>rollbacks&lt;/em> will be frequent in a timestamp scheduler.&lt;/li>
&lt;/ul>
&lt;h2 id="concurrency-control-by-validation">Concurrency Control by Validation&lt;/h2>
&lt;p>Validation differs from timestamping principally in that the scheduler maintains a record of what &lt;em>active&lt;/em> transactions are doing, rather than keeping read and write times for all database elements.&lt;/p>
&lt;p>Denote the write set and read set as $WS(T)$ and $RS(T)$. Transactions are executed in three phases:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Read&lt;/strong>. The transaction reads from the database all the elements in its read set, and also computes (locally) the results it is going to write.&lt;/li>
&lt;li>&lt;strong>Validate&lt;/strong>. The transaction compares its read and write sets with those of other transactions; rollback if fails.&lt;/li>
&lt;li>&lt;strong>Write&lt;/strong>. The transaction writes to the database the values for the elements in its write set.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>Thus, the validation-based scheduler has an assumed serial order of the transactions to work with, and it bases its decision to validate or not on whether the transactions’ behaviors are consistent with this serial order.&lt;/p>
&lt;/blockquote>
&lt;p>The scheduler maintains three sets:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>START&lt;/strong>: the set of transactions that have started, but not yet completed validation.&lt;/li>
&lt;li>&lt;strong>VAL&lt;/strong>: the set of transactions that have been validated but not yet finished the writing in phase 3.&lt;/li>
&lt;li>&lt;strong>FIN&lt;/strong>: the set of transactions that have completed phase 3.&lt;/li>
&lt;/ol>
&lt;p>Some examples:&lt;/p>
&lt;p>A later transaction might read a value before an earlier transaction writes the value.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/validate-1.webp" alt="">&lt;/p>
&lt;p>A later transaction might write before a validated, earlier transaction, as the write of the later one might occur earlier.&lt;/p>
&lt;p>&lt;img src="https://yeshe.ng/blog/2022/04/validate-2.webp" alt="">&lt;/p>
&lt;p>Summarization: to validate a transaction T:&lt;/p>
&lt;ul>
&lt;li>Check that $RS(T) \cap WS(U) = \emptyset$ for any previously validated U that did not finish before T &lt;em>started&lt;/em>, i.e., if $FIN(U) &amp;gt; START(T)$.&lt;/li>
&lt;li>Check that $WS(T) \cap WS(U) = \emptyset$ for any previously validated U that did not finish before T &lt;em>validated&lt;/em>, i.e., if $FIN(U) &amp;gt; VAL(T)$.&lt;/li>
&lt;/ul>
&lt;h2 id="comparison-of-three-concurrency-control-mechanisms">Comparison of Three Concurrency-Control Mechanisms&lt;/h2>
&lt;p>Storage: all schemes (can be optimized to) use storage space proportional to the sum over all active transactions of the number of database elements the transaction accesses.&lt;/p>
&lt;p>Performace:&lt;/p>
&lt;ul>
&lt;li>Locking delays transactions but avoids rollbacks, even when interaction is high.&lt;/li>
&lt;li>Timestamps and validation do not delay transactions, but can cause them to rollback.&lt;/li>
&lt;li>If interference is low, then neither timestamps nor validation will cause many rollbacks, and may be preferable to locking because they generally have lower overhead than a locking scheduler.&lt;/li>
&lt;li>When a rollback is necessary, timestamps catch some problems earlier than validation, which always lets a transaction do all its internal work before considering whether the transaction must rollback.&lt;/li>
&lt;/ul>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>同时执行多个事务时，需要保证每个事务的原子性，同时还必须保持一定的先后次序。&lt;/p>
&lt;p>对 schedule 最严格的要求是串行性（serial），当然这并不能做到并发。退一步，我们不需要严格保证不同事务处理的时间不互相重叠，但需要保证最终的效果和串行执行一致，即“可串行化”（serializable schedule）。当然，这个条件覆盖的范围太大，很难判断 schedule 是否满足可串行化条件。因此，我们需要增加更严格的条件，使得我们可以有简单的方法判断。当然，这样一来，满足条件的 schedule 只是可串行化 schedule 的一个真子集。&lt;/p>
&lt;p>第一大类办法是使用锁，并加上 2PL 条件，使得 schedule 满足“冲突可串行化”（confilict-serializable）。上锁有两个需要解决的问题：锁的类型及其兼容性，以及锁的粒度。&lt;/p>
&lt;p>第二大类办法是“乐观的”（optimistic），即假设不会发生不可串行化的事件，仅当的确出现违反可串行化条件时采取措施。Optimistic 方法包括两种：by timestamp，即通过比较事务开始的时间与元素被读或写的时间，判断某个操作是否可以进行；by validation，即在验证阶段比较与之前事务的读写集合判断是否可以提交，验证成功后再写入数据库。&lt;/p>
&lt;p>上锁的方法避免了重新执行，但事务会受到延迟，在冲突严重时较优；乐观方法由于可以进行一定操作，只在出现问题时取消或重新执行，因此延迟较低，但在冲突严重时会造成大量的重新执行而影响性能。&lt;/p></content></item></channel></rss>