⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mvcc.sgml

📁 PostgreSQL7.4.6 for Linux
💻 SGML
📖 第 1 页 / 共 3 页
字号:
     <tip>      <para>       Only an <literal>ACCESS EXCLUSIVE</literal> lock blocks a       <command>SELECT</command> (without <option>FOR UPDATE</option>)       statement.      </para>     </tip>   </sect2>   <sect2 id="locking-rows">    <title>Row-Level Locks</title>    <para>     In addition to table-level locks, there are row-level locks.     A row-level lock on a specific row is automatically acquired when the     row is updated (or deleted or marked for update).  The lock is held     until the transaction commits or rolls back.     Row-level locks do not affect data     querying; they block <emphasis>writers to the same row</emphasis>     only.  To acquire a row-level lock on a row without actually     modifying the row, select the row with <command>SELECT FOR     UPDATE</command>.  Note that once a particular row-level lock is     acquired, the transaction may update the row multiple times without     fear of conflicts.    </para>    <para>     <productname>PostgreSQL</productname> doesn't remember any     information about modified rows in memory, so it has no limit to     the number of rows locked at one time.  However, locking a row     may cause a disk write; thus, for example, <command>SELECT FOR     UPDATE</command> will modify selected rows to mark them and so     will result in disk writes.    </para>    <para>     In addition to table and row locks, page-level share/exclusive locks are     used to control read/write access to table pages in the shared buffer     pool.  These locks are released immediately after a row is fetched or     updated.  Application developers normally need not be concerned with     page-level locks, but we mention them for completeness.    </para>   </sect2>   <sect2 id="locking-deadlocks">    <title>Deadlocks</title>    <indexterm zone="locking-deadlocks">     <primary>deadlock</primary>    </indexterm>    <para>     The use of explicit locking can increase the likelihood of     <firstterm>deadlocks</>, wherein two (or more) transactions each     hold locks that the other wants.  For example, if transaction 1     acquires an exclusive lock on table A and then tries to acquire     an exclusive lock on table B, while transaction 2 has already     exclusive-locked table B and now wants an exclusive lock on table     A, then neither one can proceed.     <productname>PostgreSQL</productname> automatically detects     deadlock situations and resolves them by aborting one of the     transactions involved, allowing the other(s) to complete.     (Exactly which transaction will be aborted is difficult to     predict and should not be relied on.)    </para>    <para>     Note that deadlocks can also occur as the result of row-level     locks (and thus, they can occur even if explicit locking is not     used). Consider the case in which there are two concurrent     transactions modifying a table. The first transaction executes:<screen>UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 11111;</screen>     This acquires a row-level lock on the row with the specified     account number. Then, the second transaction executes:<screen>UPDATE accounts SET balance = balance + 100.00 WHERE acctnum = 22222;UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 11111;</screen>     The first <command>UPDATE</command> statement successfully     acquires a row-level lock on the specified row, so it succeeds in     updating that row. However, the second <command>UPDATE</command>     statement finds that the row it is attempting to update has     already been locked, so it waits for the transaction that     acquired the lock to complete. Transaction two is now waiting on     transaction one to complete before it continues execution. Now,     transaction one executes:<screen>UPDATE accounts SET balance = balance - 100.00 WHERE acctnum = 22222;</screen>     Transaction one attempts to acquire a row-level lock on the     specified row, but it cannot: transaction two already holds such     a lock. So it waits for transaction two to complete. Thus,     transaction one is blocked on transaction two, and transaction     two is blocked on transaction one: a deadlock     condition. <productname>PostgreSQL</productname> will detect this     situation and abort one of the transactions.    </para>    <para>     The best defense against deadlocks is generally to avoid them by     being certain that all applications using a database acquire     locks on multiple objects in a consistent order. That was the     reason for the previous deadlock example: if both transactions     had updated the rows in the same order, no deadlock would have     occurred. One should also ensure that the first lock acquired on     an object in a transaction is the highest mode that will be     needed for that object.  If it is not feasible to verify this in     advance, then deadlocks may be handled on-the-fly by retrying     transactions that are aborted due to deadlock.    </para>    <para>     So long as no deadlock situation is detected, a transaction seeking     either a table-level or row-level lock will wait indefinitely for     conflicting locks to be released.  This means it is a bad idea for     applications to hold transactions open for long periods of time     (e.g., while waiting for user input).    </para>   </sect2>  </sect1>  <sect1 id="applevel-consistency">   <title>Data Consistency Checks at the Application Level</title>   <para>    Because readers in <productname>PostgreSQL</productname>    do not lock data, regardless of    transaction isolation level, data read by one transaction can be    overwritten by another concurrent transaction. In other words,    if a row is returned by <command>SELECT</command> it doesn't mean that    the row is still current at the instant it is returned (i.e., sometime    after the current query began).  The row might have been modified or    deleted by an already-committed transaction that committed after this one    started.    Even if the row is still valid <quote>now</quote>, it could be changed or    deleted    before the current transaction does a commit or rollback.   </para>   <para>    Another way to think about it is that each    transaction sees a snapshot of the database contents, and concurrently    executing transactions may very well see different snapshots.  So the    whole concept of <quote>now</quote> is somewhat suspect anyway.    This is not normally    a big problem if the client applications are isolated from each other,    but if the clients can communicate via channels outside the database    then serious confusion may ensue.   </para>   <para>    To ensure the current validity of a row and protect it against    concurrent updates one must use <command>SELECT FOR    UPDATE</command> or an appropriate <command>LOCK TABLE</command>    statement.  (<command>SELECT FOR UPDATE</command> locks just the    returned rows against concurrent updates, while <command>LOCK    TABLE</command> locks the whole table.)  This should be taken into    account when porting applications to    <productname>PostgreSQL</productname> from other environments.    (Before version 6.5 <productname>PostgreSQL</productname> used    read locks, and so this above consideration is also relevant when    upgrading from <productname>PostgreSQL</productname> versions    prior to 6.5.)   </para>   <para>    Global validity checks require extra thought under <acronym>MVCC</acronym>.  For    example, a banking application might wish to check that the sum of    all credits in one table equals the sum of debits in another table,    when both tables are being actively updated.  Comparing the results of two    successive <literal>SELECT sum(...)</literal> commands will not work reliably under    Read Committed mode, since the second query will likely include the results    of transactions not counted by the first.  Doing the two sums in a    single serializable transaction will give an accurate picture of the    effects of transactions that committed before the serializable transaction    started --- but one might legitimately wonder whether the answer is still    relevant by the time it is delivered.  If the serializable transaction    itself applied some changes before trying to make the consistency check,    the usefulness of the check becomes even more debatable, since now it    includes some but not all post-transaction-start changes.  In such cases    a careful person might wish to lock all tables needed for the check,    in order to get an indisputable picture of current reality.  A    <literal>SHARE</> mode (or higher) lock guarantees that there are no    uncommitted changes in the locked table, other than those of the current    transaction.   </para>   <para>    Note also that if one is    relying on explicit locks to prevent concurrent changes, one should use    Read Committed mode, or in Serializable mode be careful to obtain the    lock(s) before performing queries.  An explicit lock obtained in a    serializable transaction guarantees that no other transactions modifying    the table are still running, but if the snapshot seen by the    transaction predates obtaining the lock, it may predate some now-committed    changes in the table.  A serializable transaction's snapshot is actually    frozen at the start of its first query or data-modification command    (<literal>SELECT</>, <literal>INSERT</>,    <literal>UPDATE</>, or <literal>DELETE</>), so    it's possible to obtain explicit locks before the snapshot is    frozen.   </para>  </sect1>  <sect1 id="locking-indexes">   <title>Locking and Indexes</title>   <indexterm zone="locking-indexes">    <primary>index</primary>    <secondary>locks</secondary>   </indexterm>   <para>    Though <productname>PostgreSQL</productname>    provides nonblocking read/write access to table    data, nonblocking read/write access is not currently offered for every    index access method implemented    in <productname>PostgreSQL</productname>.    The various index types are handled as follows:    <variablelist>     <varlistentry>      <term>       B-tree indexes      </term>      <listitem>       <para>	Short-term share/exclusive page-level locks are used for	read/write access. Locks are released immediately after each	index row is fetched or inserted.  B-tree indexes provide	the highest concurrency without deadlock conditions.       </para>      </listitem>     </varlistentry>     <varlistentry>      <term>       <acronym>GiST</acronym> and R-tree indexes      </term>      <listitem>       <para>	Share/exclusive index-level locks are used for read/write access.	Locks are released after the command is done.       </para>      </listitem>     </varlistentry>     <varlistentry>      <term>       Hash indexes      </term>      <listitem>       <para>	Share/exclusive page-level locks are used for read/write	access.  Locks are released after the page is processed.	Page-level locks provide better concurrency than index-level	ones but are liable to deadlocks.       </para>      </listitem>     </varlistentry>    </variablelist>   </para>   <para>    In short, B-tree indexes offer the best performance for concurrent    applications; since they also have more features than hash    indexes, they are the recommended index type for concurrent    applications that need to index scalar data. When dealing with    non-scalar data, B-trees obviously cannot be used; in that    situation, application developers should be aware of the    relatively poor concurrent performance of GiST and R-tree    indexes.   </para>  </sect1> </chapter><!-- Keep this comment at the end of the fileLocal variables:mode:sgmlsgml-omittag:nilsgml-shorttag:tsgml-minimize-attributes:nilsgml-always-quote-attributes:tsgml-indent-step:1sgml-indent-data:tsgml-parent-document:nilsgml-default-dtd-file:"./reference.ced"sgml-exposed-tags:nilsgml-local-catalogs:("/usr/lib/sgml/catalog")sgml-local-ecat-files:nilEnd:-->

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -