Author: paul
Date: 2010-07-14 17:35:58 +0200 (Wed, 14 Jul 2010)
New Revision: 21728
Log:
r61174@frost: paul | 2010-07-14 10:32:19 -0500
Some optimization chapter reorganization
Modified:
trunk/refman-4.1/data-types.xml
trunk/refman-4.1/optimization.xml
trunk/refman-4.1/renamed-nodes.txt
trunk/refman-4.1/sql-syntax-data-definition.xml
trunk/refman-5.0/data-types.xml
trunk/refman-5.0/optimization.xml
trunk/refman-5.0/renamed-nodes.txt
trunk/refman-5.0/sql-syntax-data-definition.xml
trunk/refman-5.1/data-types.xml
trunk/refman-5.1/optimization.xml
trunk/refman-5.1/renamed-nodes.txt
trunk/refman-5.1/sql-syntax-data-definition.xml
trunk/refman-5.5/data-types.xml
trunk/refman-5.5/optimization.xml
trunk/refman-5.5/renamed-nodes.txt
trunk/refman-5.5/sql-syntax-data-definition.xml
trunk/refman-6.0/data-types.xml
trunk/refman-6.0/optimization.xml
trunk/refman-6.0/sql-syntax-data-definition.xml
Property changes on: trunk
___________________________________________________________________
Name: svk:merge
- 07c7e7b4-24e3-4b51-89d0-6dc09fec6bec:/mysqldoc-local/mysqldoc/trunk:35498
07c7e7b4-24e3-4b51-89d0-6dc09fec6bec:/mysqldoc-local/trunk:40851
4767c598-dc10-0410-bea0-d01b485662eb:/mysqldoc-local/mysqldoc/trunk:43968
4767c598-dc10-0410-bea0-d01b485662eb:/mysqldoc-local/trunk:44480
7d8d2c4e-af1d-0410-ab9f-b038ce55645b:/mysqldoc-local/mysqldoc:61170
b5ec3a16-e900-0410-9ad2-d183a3acac99:/mysqldoc-local/mysqldoc/trunk:14218
bf112a9c-6c03-0410-a055-ad865cd57414:/mysqldoc-local/mysqldoc/trunk:39036
bf112a9c-6c03-0410-a055-ad865cd57414:/mysqldoc-local/trunk:39546
+ 07c7e7b4-24e3-4b51-89d0-6dc09fec6bec:/mysqldoc-local/mysqldoc/trunk:35498
07c7e7b4-24e3-4b51-89d0-6dc09fec6bec:/mysqldoc-local/trunk:40851
4767c598-dc10-0410-bea0-d01b485662eb:/mysqldoc-local/mysqldoc/trunk:43968
4767c598-dc10-0410-bea0-d01b485662eb:/mysqldoc-local/trunk:44480
7d8d2c4e-af1d-0410-ab9f-b038ce55645b:/mysqldoc-local/mysqldoc:61174
b5ec3a16-e900-0410-9ad2-d183a3acac99:/mysqldoc-local/mysqldoc/trunk:14218
bf112a9c-6c03-0410-a055-ad865cd57414:/mysqldoc-local/mysqldoc/trunk:39036
bf112a9c-6c03-0410-a055-ad865cd57414:/mysqldoc-local/trunk:39546
Modified: trunk/refman-4.1/data-types.xml
===================================================================
--- trunk/refman-4.1/data-types.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-4.1/data-types.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 594 bytes
@@ -5115,7 +5115,7 @@
specify an index prefix length. For
<literal role="type">CHAR</literal> and
<literal role="type">VARCHAR</literal>, a prefix length is
- optional. See <xref linkend="indexes"/>.
+ optional. See <xref linkend="column-indexes"/>.
</para>
</listitem>
Modified: trunk/refman-4.1/optimization.xml
===================================================================
--- trunk/refman-4.1/optimization.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-4.1/optimization.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 3, Lines Added: 1104, Lines Deleted: 1098; 79638 bytes
@@ -5277,1106 +5277,12 @@
</section>
- <section id="locking-issues">
+ <section id="optimization-indexes">
- <title>Locking Issues</title>
+ <title>Optimization and Indexes</title>
- <para>
- MySQL manages contention for table contents using locking:
- </para>
+ <section id="column-indexes">
- <itemizedlist>
-
- <listitem>
- <para>
- Internal locking is performed within the MySQL server itself
- to manage contention for table contents by multiple threads.
- This type of locking is internal because it is performed
- entirely by the server and involves no other programs. See
- <xref linkend="internal-locking"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- External locking occurs when the server and other programs
- lock table files to coordinate among themselves which program
- can access the tables at which time. See
- <xref linkend="external-locking"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <section id="internal-locking">
-
- <title>Internal Locking Methods</title>
-
- <indexterm>
- <primary>internal locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>internal</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking methods</primary>
- </indexterm>
-
- <indexterm>
- <primary>methods</primary>
- <secondary>locking</secondary>
- </indexterm>
-
- <indexterm>
- <primary>row-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>page-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>table-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>row-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>page-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>table-level</secondary>
- </indexterm>
-
- <para>
- This section discusses internal locking; that is, locking
- performed within the MySQL server itself to manage contention
- for table contents by multiple sessions. This type of locking is
- internal because it is performed entirely by the server and
- involves no other programs. External locking occurs when the
- server and other programs lock table files to coordinate among
- themselves which program can access the tables at which time.
- See <xref linkend="external-locking"/>.
- </para>
-
- <para>
- MySQL uses table-level locking for <literal>ISAM</literal>,
- <literal>MyISAM</literal>, <literal>MEMORY</literal>
- (<literal>HEAP</literal>), and <literal>MERGE</literal> tables,
- page-level locking for <literal>BDB</literal> tables, and
- row-level locking for <literal>InnoDB</literal> tables.
- </para>
-
- <para>
- In many cases, you can make an educated guess about which
- locking type is best for an application, but generally it is
- difficult to say that a given lock type is better than another.
- Everything depends on the application and different parts of an
- application may require different lock types.
- </para>
-
- <para>
- To decide whether you want to use a storage engine with
- row-level locking, you should look at what your application does
- and what mix of select and update statements it uses. For
- example, most Web applications perform many selects, relatively
- few deletes, updates based mainly on key values, and inserts
- into a few specific tables. The base MySQL
- <literal>MyISAM</literal> setup is very well tuned for this.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- The MySQL Enterprise Monitor provides expert advice on when to
- use table-level locking and when to use row-level locking. To
- subscribe, see &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
-
- <para>
- Table locking in MySQL is deadlock-free for storage engines that
- use table-level locking. Deadlock avoidance is managed by always
- requesting all needed locks at once at the beginning of a query
- and always locking the tables in the same order.
- </para>
-
- <para>
- MySQL grants table write locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no locks on the table, put a write lock on it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the write lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- MySQL grants table read locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no write locks on the table, put a read lock on
- it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the read lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- Table updates are given higher priority than table retrievals.
- Therefore, when a lock is released, the lock is made available
- to the requests in the write lock queue and then to the requests
- in the read lock queue. This ensures that updates to a table are
- not <quote>starved</quote> even if there is heavy
- <literal role="stmt">SELECT</literal> activity for the table.
- However, if you have many updates for a table,
- <literal role="stmt">SELECT</literal> statements wait until
- there are no more updates.
- </para>
-
- <para>
- For information on altering the priority of reads and writes,
- see <xref linkend="table-locking"/>.
- </para>
-
- <para>
- Starting in MySQL 3.23.33, you can analyze the table lock
- contention on your system by checking the
- <literal role="statvar">Table_locks_immediate</literal> and
- <literal role="statvar">Table_locks_waited</literal> status
- variables, which indicate the number of times that requests for
- table locks could be granted immediately and the number that had
- to wait, respectively:
- </para>
-
-<programlisting>
-mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
-+-----------------------+---------+
-| Variable_name | Value |
-+-----------------------+---------+
-| Table_locks_immediate | 1151552 |
-| Table_locks_waited | 15324 |
-+-----------------------+---------+
-</programlisting>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- As of MySQL 3.23.7 (3.23.25 for Windows), the
- <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no free
- blocks in the middle of the data file, rows are always inserted
- at the end of the data file. In this case, you can freely mix
- concurrent <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> statements for a
- <literal>MyISAM</literal> table without locks. That is, you can
- insert rows into a <literal>MyISAM</literal> table at the same
- time other clients are reading from it. (Holes can result from
- rows having been deleted from or updated in the middle of the
- table. If there are holes, concurrent inserts are disabled but
- are enabled again automatically when all holes have been filled
- with new data.)
- </para>
-
- <para>
- If you acquire a table lock explicitly with
- <literal role="stmt">LOCK TABLES</literal>, you can request a
- <literal>READ LOCAL</literal> lock rather than a
- <literal>READ</literal> lock to enable other sessions to perform
- concurrent inserts while you have the table locked.
- </para>
-
- <para>
- To perform many <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> operations on a table
- <literal>real_table</literal> when concurrent inserts are not
- possible, you can insert rows into a temporary table
- <literal>temp_table</literal> and update the real table with the
- rows from the temporary table periodically. This can be done
- with the following code:
- </para>
-
-<programlisting>
-mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
-mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
-mysql> <userinput>DELETE FROM temp_table;</userinput>
-mysql> <userinput>UNLOCK TABLES;</userinput>
-</programlisting>
-
- <para>
- <literal>InnoDB</literal> uses row locks and
- <literal>BDB</literal> uses page locks. Deadlocks are possible
- for these storage engines because they automatically acquire
- locks during the processing of SQL statements, not at the start
- of the transaction.
- </para>
-
- <para>
- Advantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Fewer lock conflicts when different sessions access
- different rows
- </para>
- </listitem>
-
- <listitem>
- <para>
- Fewer changes for rollbacks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Possible to lock a single row for a long time
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Disadvantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Requires more memory than page-level or table-level locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than page-level or table-level locks when used on a
- large part of the table because you must acquire many more
- locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than other locks if you often do <literal>GROUP
- BY</literal> operations on a large part of the data or if
- you must scan the entire table frequently
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Generally, table locks are superior to page-level or row-level
- locks in the following cases:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Most statements for the table are reads
- </para>
- </listitem>
-
- <listitem>
- <para>
- Statements for the table are a mix of reads and writes,
- where writes are updates or deletes for a single row that
- can be fetched with one key read:
- </para>
-
-<programlisting>
-UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-</programlisting>
- </listitem>
-
- <listitem>
- <para>
- <literal role="stmt">SELECT</literal> combined with
- concurrent <literal role="stmt">INSERT</literal> statements,
- and very few <literal role="stmt">UPDATE</literal> or
- <literal role="stmt">DELETE</literal> statements
- </para>
- </listitem>
-
- <listitem>
- <para>
- Many scans or <literal>GROUP BY</literal> operations on the
- entire table without any writers
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With higher-level locks, you can more easily tune applications
- by supporting locks of different types, because the lock
- overhead is less than for row-level locks.
- </para>
-
- <para>
- Options other than row-level or page-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Versioning (such as that used in MySQL for concurrent
- inserts) where it is possible to have one writer at the same
- time as many readers. This means that the database or table
- supports different views for the data depending on when
- access begins. Other common terms for this are <quote>time
- travel,</quote> <quote>copy on write,</quote> or <quote>copy
- on demand.</quote>
- </para>
- </listitem>
-
- <listitem>
- <para>
- Copy on demand is in many cases superior to page-level or
- row-level locking. However, in the worst case, it can use
- much more memory than using normal locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Instead of using row-level locks, you can employ
- application-level locks, such as those provided by
- <literal role="func">GET_LOCK()</literal> and
- <literal role="func">RELEASE_LOCK()</literal> in MySQL.
- These are advisory locks, so they work only with
- applications that cooperate with each other. See
- <xref linkend="miscellaneous-functions"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="table-locking">
-
- <title>Table Locking Issues</title>
-
- <indexterm>
- <primary>problems</primary>
- <secondary>table locking</secondary>
- </indexterm>
-
- <para>
- To achieve a very high lock speed, MySQL uses table locking
- (instead of page, row, or column locking) for all storage
- engines except <literal>InnoDB</literal>,
- <literal>BDB</literal>, and
- <literal role="se">NDBCLUSTER</literal>.
- </para>
-
- <para>
- For <literal>InnoDB</literal> and <literal>BDB</literal> tables,
- MySQL uses table locking only if you explicitly lock the table
- with <literal role="stmt">LOCK TABLES</literal>. For these
- storage engines, avoid using <literal role="stmt">LOCK
- TABLES</literal> at all, because <literal>InnoDB</literal> uses
- automatic row-level locking and <literal>BDB</literal> uses
- page-level locking to ensure transaction isolation.
- </para>
-
- <para>
- For large tables, table locking is often better than row
- locking, but there are some disadvantages:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Table locking enables many sessions to read from a table at
- the same time, but if a session wants to write to a table,
- it must first get exclusive access. During the update, all
- other sessions that want to access this particular table
- must wait until the update is done.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Table locking causes problems in cases such as when a
- session is waiting because the disk is full and free space
- needs to become available before the session can proceed. In
- this case, all sessions that want to access the problem
- table are also put in a waiting state until more disk space
- is made available.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Table locking is also disadvantageous under the following
- scenario:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A session issues a <literal role="stmt">SELECT</literal>
- that takes a long time to run.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session then issues an
- <literal role="stmt">UPDATE</literal> on the same table.
- This session waits until the
- <literal role="stmt">SELECT</literal> is finished.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session issues another
- <literal role="stmt">SELECT</literal> statement on the same
- table. Because <literal role="stmt">UPDATE</literal> has
- higher priority than <literal role="stmt">SELECT</literal>,
- this <literal role="stmt">SELECT</literal> waits for the
- <literal role="stmt">UPDATE</literal> to finish,
- <emphasis>after</emphasis> waiting for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following items describe some ways to avoid or reduce
- contention caused by table locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Try to get the <literal role="stmt">SELECT</literal>
- statements to run faster so that they lock tables for a
- shorter time. You might have to create some summary tables
- to do this.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with
- <option role="mysqld">--low-priority-updates</option>. For
- storage engines that use only table-level locking (such as
- <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
- <literal>MERGE</literal>), this gives all statements that
- update (modify) a table lower priority than
- <literal role="stmt">SELECT</literal> statements. In this
- case, the second <literal role="stmt">SELECT</literal>
- statement in the preceding scenario would execute before the
- <literal role="stmt">UPDATE</literal> statement, and would
- not need to wait for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To specify that all updates issued in a specific connection
- should be done with low priority, set the
- <literal role="sysvar">low_priority_updates</literal> server
- system variable equal to 1.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">INSERT</literal>,
- <literal role="stmt">UPDATE</literal>, or
- <literal role="stmt">DELETE</literal> statement lower
- priority, use the <literal>LOW_PRIORITY</literal> attribute.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">SELECT</literal>
- statement higher priority, use the
- <literal>HIGH_PRIORITY</literal> attribute. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Starting from MySQL 3.23.7, you can start
- <command>mysqld</command> with a low value for the
- <literal role="sysvar">max_write_lock_count</literal> system
- variable to force MySQL to temporarily elevate the priority
- of all <literal role="stmt">SELECT</literal> statements that
- are waiting for a table after a specific number of inserts
- to the table occur. This permits <literal>READ</literal>
- locks after a certain number of <literal>WRITE</literal>
- locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with
- <literal role="stmt">INSERT</literal> combined with
- <literal role="stmt">SELECT</literal>, consider switching to
- <literal>MyISAM</literal> tables, which support concurrent
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">INSERT</literal> statements. (See
- <xref linkend="concurrent-inserts"/>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you mix inserts and deletes on the same table,
- <literal role="stmt">INSERT DELAYED</literal> may be of
- great help. See <xref linkend="insert-delayed"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with mixed
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">DELETE</literal> statements, the
- <literal>LIMIT</literal> option to
- <literal role="stmt">DELETE</literal> may help. See
- <xref linkend="delete"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Using <literal>SQL_BUFFER_RESULT</literal> with
- <literal role="stmt">SELECT</literal> statements can help to
- make the duration of table locks shorter. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You could change the locking code in
- <filename>mysys/thr_lock.c</filename> to use a single queue.
- In this case, write locks and read locks would have the same
- priority, which might help some applications.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Here are some tips concerning table locks in MySQL:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Concurrent users are not a problem if you do not mix updates
- with selects that need to examine many rows in the same
- table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can use <literal role="stmt">LOCK TABLES</literal> to
- increase speed, because many updates within a single lock is
- much faster than updating without locks. Splitting table
- contents into separate tables may also help.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you encounter speed problems with table locks in MySQL,
- you may be able to improve performance by converting some of
- your tables to <literal>InnoDB</literal> or
- <literal>BDB</literal> tables. See <xref linkend="innodb"/>,
- and <xref linkend="bdb-storage-engine"/>.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- Lock contention can seriously degrade performance. The
- MySQL Enterprise Monitor provides expert advice on
- avoiding this problem. To subscribe, see
- &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="concurrent-inserts">
-
- <title>Concurrent Inserts</title>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- As of MySQL 3.23.7 (3.23.25 for Windows), the
- <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no holes
- in the data file (deleted rows in the middle), an
- <literal role="stmt">INSERT</literal> statement can be executed
- to add rows to the end of the table at the same time that
- <literal role="stmt">SELECT</literal> statements are reading
- rows from the table. If there are multiple
- <literal role="stmt">INSERT</literal> statements, they are
- queued and performed in sequence, concurrently with the
- <literal role="stmt">SELECT</literal> statements. The results of
- a concurrent <literal role="stmt">INSERT</literal> may not be
- visible immediately.
- </para>
-
- <para>
- Concurrent inserts are enabled by default, but can be disabled
- by setting the
- <literal role="sysvar">concurrent_insert</literal> system
- variable to 0.
- </para>
-
- <para>
- Under circumstances where concurrent inserts can be used, there
- is seldom any need to use the <literal>DELAYED</literal>
- modifier for <literal role="stmt">INSERT</literal> statements.
- See <xref linkend="insert-delayed"/>.
- </para>
-
- <para>
- If you are using the update log or binary log, concurrent
- inserts are converted to normal inserts for <literal>CREATE ...
- SELECT</literal> or
- <literal role="stmt" condition="insert-select">INSERT ...
- SELECT</literal> statements. This is done to ensure that you can
- re-create an exact copy of your tables by applying the log
- during a backup operation. See <xref linkend="binary-log"/>. In
- addition, for those statements a read lock is placed on the
- selected-from table such that inserts into that table are
- blocked. The effect is that concurrent inserts for that table
- must wait as well.
- </para>
-
- <para>
- With <literal role="stmt" condition="load-data">LOAD DATA
- INFILE</literal>, if you specify <literal>CONCURRENT</literal>
- with a <literal>MyISAM</literal> table that satisfies the
- condition for concurrent inserts (that is, it contains no free
- blocks in the middle), other sessions can retrieve data from the
- table while <literal role="stmt">LOAD DATA</literal> is
- executing. Use of the <literal>CONCURRENT</literal> option
- affects the performance of <literal role="stmt">LOAD
- DATA</literal> a bit, even if no other session is using the
- table at the same time.
- </para>
-
- <para>
- If you specify <literal>HIGH_PRIORITY</literal>, it overrides
- the effect of the
- <option role="mysqld">--low-priority-updates</option> option if
- the server was started with that option. It also causes
- concurrent inserts not to be used.
- </para>
-
- <para>
- For <literal role="stmt" condition="lock-tables">LOCK
- TABLE</literal>, the difference between <literal>READ
- LOCAL</literal> and <literal>READ</literal> is that
- <literal>READ LOCAL</literal> permits nonconflicting
- <literal role="stmt">INSERT</literal> statements (concurrent
- inserts) to execute while the lock is held. However, this cannot
- be used if you are going to manipulate the database using
- processes external to the server while you hold the lock.
- </para>
-
- </section>
-
- <section id="external-locking">
-
- <title>External Locking</title>
-
- <indexterm>
- <primary>external locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>external</secondary>
- </indexterm>
-
- <para>
- External locking is the use of file system locking to manage
- contention for database tables by multiple processes. External
- locking is used in situations where a single process such as the
- MySQL server cannot be assumed to be the only process that
- requires access to tables. Here are some examples:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- If you run multiple servers that use the same database
- directory (not recommended), each server must have external
- locking enabled.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you use <command>myisamchk</command> to perform table
- maintenance operations on <literal>MyISAM</literal> tables,
- you must either ensure that the server is not running, or
- that the server has external locking enabled so that it
- locks table files as necessary to coordinate with
- <command>myisamchk</command> for access to the tables. The
- same is true for use of <command>myisampack</command> to
- pack <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- If the server is run with external locking enabled, you can
- use <command>myisamchk</command> at any time for read
- operations such a checking tables. In this case, if the
- server tries to update a table that
- <command>myisamchk</command> is using, the server will wait
- for <command>myisamchk</command> to finish before it
- continues.
- </para>
-
- <para>
- If you use <command>myisamchk</command> for write operations
- such as repairing or optimizing tables, or if you use
- <command>myisampack</command> to pack tables, you
- <emphasis>must</emphasis> always ensure that the
- <command>mysqld</command> server is not using the table. If
- you don't stop <command>mysqld</command>, you should at
- least do a <command>mysqladmin flush-tables</command> before
- you run <command>myisamchk</command>. Your tables
- <emphasis>may become corrupted</emphasis> if the server and
- <command>myisamchk</command> access the tables
- simultaneously.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With external locking in effect, each process that requires
- access to a table acquires a file system lock for the table
- files before proceeding to access the table. If all necessary
- locks cannot be acquired, the process is blocked from accessing
- the table until the locks can be obtained (after the process
- that currently holds the locks releases them).
- </para>
-
- <para>
- External locking affects server performance because the server
- must sometimes wait for other processes before it can access
- tables.
- </para>
-
- <para>
- External locking is unnecessary if you run a single server to
- access a given data directory (which is the usual case) and if
- no other programs such as <command>myisamchk</command> need to
- modify tables while the server is running. If you only
- <emphasis>read</emphasis> tables with other programs, external
- locking is not required, although <command>myisamchk</command>
- might report warnings if the server changes tables while
- <command>myisamchk</command> is reading them.
- </para>
-
- <para>
- With external locking disabled, to use
- <command>myisamchk</command>, you must either stop the server
- while <command>myisamchk</command> executes or else lock and
- flush the tables before running <command>myisamchk</command>.
- (See <xref linkend="system-optimization"/>.) To avoid this
- requirement as of MySQL 3.23, use the <literal role="stmt">CHECK
- TABLE</literal> and <literal role="stmt">REPAIR TABLE</literal>
- statements to check and repair <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- For <command>mysqld</command>, external locking is controlled by
- the value of the
- <literal role="sysvar">skip_external_locking</literal> system
- variable. (Before MySQL 4.0.3, this variable is named
- <literal>skip_locking</literal>.) When this variable is enabled,
- external locking is disabled, and vice versa. From MySQL 4.0 on,
- external locking is disabled by default. Before MySQL 4.0,
- external locking is enabled by default on Linux or when MySQL is
- configured to use MIT-pthreads.
- </para>
-
- <para>
- Use of external locking can be controlled at server startup by
- using the <option role="mysqld">--external-locking</option> or
- <option role="mysqld">--skip-external-locking</option> option.
- (Before MySQL 4.0.3, these options are named
- <option>--enable-locking</option> and
- <option>--skip-locking</option>.)
- </para>
-
- <para>
- If you do use external locking option to enable updates to
- <literal>MyISAM</literal> tables from many MySQL processes, you
- must ensure that the following conditions are satisfied:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- You should not use the query cache for queries that use
- tables that are updated by another process.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You should not start the server with the
- <option role="mysqld">--delay-key-write=ALL</option> option
- or use the <literal>DELAY_KEY_WRITE=1</literal> table option
- for any shared tables. Otherwise, index corruption can
- occur.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The easiest way to satisfy these conditions is to always use
- <option role="mysqld">--external-locking</option> together with
- <option role="mysqld">--delay-key-write=OFF</option> and
- <option role="sysvar">--query-cache-size=0</option>. (This is
- not done by default because in many setups it is useful to have
- a mixture of the preceding options.)
- </para>
-
- </section>
-
- </section>
-
- <section id="optimizing-database-structure">
-
- <title>Optimizing Database Structure</title>
-
- <section id="data-size">
-
- <title>Make Your Data as Small as Possible</title>
-
- <indexterm>
- <primary>data</primary>
- <secondary>size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>reducing</primary>
- <secondary>data size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>storage space</primary>
- <secondary>minimizing</secondary>
- </indexterm>
-
- <indexterm>
- <primary>tables</primary>
- <secondary>improving performance</secondary>
- </indexterm>
-
- <indexterm>
- <primary>performance</primary>
- <secondary>improving</secondary>
- </indexterm>
-
- <para>
- One of the most basic optimizations is to design your tables to
- take as little space on the disk as possible. This can result in
- huge improvements because disk reads are faster, and smaller
- tables normally require less main memory while their contents
- are being actively processed during query execution. Indexing
- also is a lesser resource burden if done on smaller columns.
- </para>
-
- <para>
- MySQL supports many different storage engines (table types) and
- row formats. For each table, you can decide which storage and
- indexing method to use. Choosing the proper table format for
- your application may give you a big performance gain. See
- <xref linkend="storage-engines"/>.
- </para>
-
- <para>
- You can get better performance for a table and minimize storage
- space by using the techniques listed here:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Use the most efficient (smallest) data types possible. MySQL
- has many specialized types that save disk space and memory.
- For example, use the smaller integer types if possible to
- get smaller tables. <literal role="type">MEDIUMINT</literal>
- is often a better choice than
- <literal role="type">INT</literal> because a
- <literal role="type">MEDIUMINT</literal> column uses 25%
- less space.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Declare columns to be <literal>NOT NULL</literal> if
- possible. It makes everything faster and you save one bit
- per column. If you really need <literal>NULL</literal> in
- your application, you should definitely use it. Just avoid
- having it on all columns by default.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For <literal>MyISAM</literal> tables, if you do not have any
- variable-length columns
- (<literal role="type">VARCHAR</literal>,
- <literal role="type">TEXT</literal>, or
- <literal role="type">BLOB</literal> columns), a fixed-size
- row format is used. This is faster but unfortunately may
- waste some space. See
- <xref linkend="myisam-table-formats"/>. You can hint that
- you want to have fixed length rows even if you have
- <literal role="type">VARCHAR</literal> columns with the
- <literal role="stmt">CREATE TABLE</literal> option
- <literal>ROW_FORMAT=FIXED</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- The primary index of a table should be as short as possible.
- This makes identification of each row easy and efficient.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Create only the indexes that you really need. Indexes are
- good for retrieval but bad when you need to store data
- quickly. If you access a table mostly by searching on a
- combination of columns, create an index on them. The first
- part of the index should be the column most used. If you
- <emphasis>always</emphasis> use many columns when selecting
- from the table, the first column in the index should be the
- one with the most duplicates to obtain better compression of
- the index.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If it is very likely that a string column has a unique
- prefix on the first number of characters, it is better to
- index only this prefix, using MySQL's support for creating
- an index on the leftmost part of the column (see
- <xref linkend="create-index"/>). Shorter indexes are faster,
- not only because they require less disk space, but because
- they also give you more hits in the index cache, and thus
- fewer disk seeks. See <xref linkend="server-parameters"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- In some circumstances, it can be beneficial to split into
- two a table that is scanned very often. This is especially
- true if it is a dynamic-format table and it is possible to
- use a smaller static format table that can be used to find
- the relevant rows when scanning the table.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="indexes">
-
<title>Column Indexes</title>
<indexterm>
@@ -6502,7 +5408,7 @@
MySQL can create composite indexes (that is, indexes on multiple
columns). An index may consist of up to 16 columns. For certain
data types, you can index a prefix of the column (see
- <xref linkend="indexes"/>).
+ <xref linkend="column-indexes"/>).
</para>
<para>
@@ -8055,6 +6961,1106 @@
</section>
+ </section>
+
+ <section id="locking-issues">
+
+ <title>Locking Issues</title>
+
+ <para>
+ MySQL manages contention for table contents using locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Internal locking is performed within the MySQL server itself
+ to manage contention for table contents by multiple threads.
+ This type of locking is internal because it is performed
+ entirely by the server and involves no other programs. See
+ <xref linkend="internal-locking"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ External locking occurs when the server and other programs
+ lock table files to coordinate among themselves which program
+ can access the tables at which time. See
+ <xref linkend="external-locking"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <section id="internal-locking">
+
+ <title>Internal Locking Methods</title>
+
+ <indexterm>
+ <primary>internal locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>internal</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking methods</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>methods</primary>
+ <secondary>locking</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>page-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>table-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>row-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>page-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>table-level</secondary>
+ </indexterm>
+
+ <para>
+ This section discusses internal locking; that is, locking
+ performed within the MySQL server itself to manage contention
+ for table contents by multiple sessions. This type of locking is
+ internal because it is performed entirely by the server and
+ involves no other programs. External locking occurs when the
+ server and other programs lock table files to coordinate among
+ themselves which program can access the tables at which time.
+ See <xref linkend="external-locking"/>.
+ </para>
+
+ <para>
+ MySQL uses table-level locking for <literal>ISAM</literal>,
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>
+ (<literal>HEAP</literal>), and <literal>MERGE</literal> tables,
+ page-level locking for <literal>BDB</literal> tables, and
+ row-level locking for <literal>InnoDB</literal> tables.
+ </para>
+
+ <para>
+ In many cases, you can make an educated guess about which
+ locking type is best for an application, but generally it is
+ difficult to say that a given lock type is better than another.
+ Everything depends on the application and different parts of an
+ application may require different lock types.
+ </para>
+
+ <para>
+ To decide whether you want to use a storage engine with
+ row-level locking, you should look at what your application does
+ and what mix of select and update statements it uses. For
+ example, most Web applications perform many selects, relatively
+ few deletes, updates based mainly on key values, and inserts
+ into a few specific tables. The base MySQL
+ <literal>MyISAM</literal> setup is very well tuned for this.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ The MySQL Enterprise Monitor provides expert advice on when to
+ use table-level locking and when to use row-level locking. To
+ subscribe, see &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+
+ <para>
+ Table locking in MySQL is deadlock-free for storage engines that
+ use table-level locking. Deadlock avoidance is managed by always
+ requesting all needed locks at once at the beginning of a query
+ and always locking the tables in the same order.
+ </para>
+
+ <para>
+ MySQL grants table write locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no locks on the table, put a write lock on it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the write lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ MySQL grants table read locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no write locks on the table, put a read lock on
+ it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the read lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ Table updates are given higher priority than table retrievals.
+ Therefore, when a lock is released, the lock is made available
+ to the requests in the write lock queue and then to the requests
+ in the read lock queue. This ensures that updates to a table are
+ not <quote>starved</quote> even if there is heavy
+ <literal role="stmt">SELECT</literal> activity for the table.
+ However, if you have many updates for a table,
+ <literal role="stmt">SELECT</literal> statements wait until
+ there are no more updates.
+ </para>
+
+ <para>
+ For information on altering the priority of reads and writes,
+ see <xref linkend="table-locking"/>.
+ </para>
+
+ <para>
+ Starting in MySQL 3.23.33, you can analyze the table lock
+ contention on your system by checking the
+ <literal role="statvar">Table_locks_immediate</literal> and
+ <literal role="statvar">Table_locks_waited</literal> status
+ variables, which indicate the number of times that requests for
+ table locks could be granted immediately and the number that had
+ to wait, respectively:
+ </para>
+
+<programlisting>
+mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
++-----------------------+---------+
+| Variable_name | Value |
++-----------------------+---------+
+| Table_locks_immediate | 1151552 |
+| Table_locks_waited | 15324 |
++-----------------------+---------+
+</programlisting>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ As of MySQL 3.23.7 (3.23.25 for Windows), the
+ <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no free
+ blocks in the middle of the data file, rows are always inserted
+ at the end of the data file. In this case, you can freely mix
+ concurrent <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> statements for a
+ <literal>MyISAM</literal> table without locks. That is, you can
+ insert rows into a <literal>MyISAM</literal> table at the same
+ time other clients are reading from it. (Holes can result from
+ rows having been deleted from or updated in the middle of the
+ table. If there are holes, concurrent inserts are disabled but
+ are enabled again automatically when all holes have been filled
+ with new data.)
+ </para>
+
+ <para>
+ If you acquire a table lock explicitly with
+ <literal role="stmt">LOCK TABLES</literal>, you can request a
+ <literal>READ LOCAL</literal> lock rather than a
+ <literal>READ</literal> lock to enable other sessions to perform
+ concurrent inserts while you have the table locked.
+ </para>
+
+ <para>
+ To perform many <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> operations on a table
+ <literal>real_table</literal> when concurrent inserts are not
+ possible, you can insert rows into a temporary table
+ <literal>temp_table</literal> and update the real table with the
+ rows from the temporary table periodically. This can be done
+ with the following code:
+ </para>
+
+<programlisting>
+mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
+mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
+mysql> <userinput>DELETE FROM temp_table;</userinput>
+mysql> <userinput>UNLOCK TABLES;</userinput>
+</programlisting>
+
+ <para>
+ <literal>InnoDB</literal> uses row locks and
+ <literal>BDB</literal> uses page locks. Deadlocks are possible
+ for these storage engines because they automatically acquire
+ locks during the processing of SQL statements, not at the start
+ of the transaction.
+ </para>
+
+ <para>
+ Advantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Fewer lock conflicts when different sessions access
+ different rows
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fewer changes for rollbacks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Possible to lock a single row for a long time
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Disadvantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Requires more memory than page-level or table-level locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than page-level or table-level locks when used on a
+ large part of the table because you must acquire many more
+ locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than other locks if you often do <literal>GROUP
+ BY</literal> operations on a large part of the data or if
+ you must scan the entire table frequently
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Generally, table locks are superior to page-level or row-level
+ locks in the following cases:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Most statements for the table are reads
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Statements for the table are a mix of reads and writes,
+ where writes are updates or deletes for a single row that
+ can be fetched with one key read:
+ </para>
+
+<programlisting>
+UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal role="stmt">SELECT</literal> combined with
+ concurrent <literal role="stmt">INSERT</literal> statements,
+ and very few <literal role="stmt">UPDATE</literal> or
+ <literal role="stmt">DELETE</literal> statements
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Many scans or <literal>GROUP BY</literal> operations on the
+ entire table without any writers
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With higher-level locks, you can more easily tune applications
+ by supporting locks of different types, because the lock
+ overhead is less than for row-level locks.
+ </para>
+
+ <para>
+ Options other than row-level or page-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Versioning (such as that used in MySQL for concurrent
+ inserts) where it is possible to have one writer at the same
+ time as many readers. This means that the database or table
+ supports different views for the data depending on when
+ access begins. Other common terms for this are <quote>time
+ travel,</quote> <quote>copy on write,</quote> or <quote>copy
+ on demand.</quote>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Copy on demand is in many cases superior to page-level or
+ row-level locking. However, in the worst case, it can use
+ much more memory than using normal locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Instead of using row-level locks, you can employ
+ application-level locks, such as those provided by
+ <literal role="func">GET_LOCK()</literal> and
+ <literal role="func">RELEASE_LOCK()</literal> in MySQL.
+ These are advisory locks, so they work only with
+ applications that cooperate with each other. See
+ <xref linkend="miscellaneous-functions"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="table-locking">
+
+ <title>Table Locking Issues</title>
+
+ <indexterm>
+ <primary>problems</primary>
+ <secondary>table locking</secondary>
+ </indexterm>
+
+ <para>
+ To achieve a very high lock speed, MySQL uses table locking
+ (instead of page, row, or column locking) for all storage
+ engines except <literal>InnoDB</literal>,
+ <literal>BDB</literal>, and
+ <literal role="se">NDBCLUSTER</literal>.
+ </para>
+
+ <para>
+ For <literal>InnoDB</literal> and <literal>BDB</literal> tables,
+ MySQL uses table locking only if you explicitly lock the table
+ with <literal role="stmt">LOCK TABLES</literal>. For these
+ storage engines, avoid using <literal role="stmt">LOCK
+ TABLES</literal> at all, because <literal>InnoDB</literal> uses
+ automatic row-level locking and <literal>BDB</literal> uses
+ page-level locking to ensure transaction isolation.
+ </para>
+
+ <para>
+ For large tables, table locking is often better than row
+ locking, but there are some disadvantages:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Table locking enables many sessions to read from a table at
+ the same time, but if a session wants to write to a table,
+ it must first get exclusive access. During the update, all
+ other sessions that want to access this particular table
+ must wait until the update is done.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Table locking causes problems in cases such as when a
+ session is waiting because the disk is full and free space
+ needs to become available before the session can proceed. In
+ this case, all sessions that want to access the problem
+ table are also put in a waiting state until more disk space
+ is made available.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Table locking is also disadvantageous under the following
+ scenario:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ A session issues a <literal role="stmt">SELECT</literal>
+ that takes a long time to run.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session then issues an
+ <literal role="stmt">UPDATE</literal> on the same table.
+ This session waits until the
+ <literal role="stmt">SELECT</literal> is finished.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session issues another
+ <literal role="stmt">SELECT</literal> statement on the same
+ table. Because <literal role="stmt">UPDATE</literal> has
+ higher priority than <literal role="stmt">SELECT</literal>,
+ this <literal role="stmt">SELECT</literal> waits for the
+ <literal role="stmt">UPDATE</literal> to finish,
+ <emphasis>after</emphasis> waiting for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following items describe some ways to avoid or reduce
+ contention caused by table locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Try to get the <literal role="stmt">SELECT</literal>
+ statements to run faster so that they lock tables for a
+ shorter time. You might have to create some summary tables
+ to do this.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with
+ <option role="mysqld">--low-priority-updates</option>. For
+ storage engines that use only table-level locking (such as
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
+ <literal>MERGE</literal>), this gives all statements that
+ update (modify) a table lower priority than
+ <literal role="stmt">SELECT</literal> statements. In this
+ case, the second <literal role="stmt">SELECT</literal>
+ statement in the preceding scenario would execute before the
+ <literal role="stmt">UPDATE</literal> statement, and would
+ not need to wait for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To specify that all updates issued in a specific connection
+ should be done with low priority, set the
+ <literal role="sysvar">low_priority_updates</literal> server
+ system variable equal to 1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">INSERT</literal>,
+ <literal role="stmt">UPDATE</literal>, or
+ <literal role="stmt">DELETE</literal> statement lower
+ priority, use the <literal>LOW_PRIORITY</literal> attribute.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">SELECT</literal>
+ statement higher priority, use the
+ <literal>HIGH_PRIORITY</literal> attribute. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Starting from MySQL 3.23.7, you can start
+ <command>mysqld</command> with a low value for the
+ <literal role="sysvar">max_write_lock_count</literal> system
+ variable to force MySQL to temporarily elevate the priority
+ of all <literal role="stmt">SELECT</literal> statements that
+ are waiting for a table after a specific number of inserts
+ to the table occur. This permits <literal>READ</literal>
+ locks after a certain number of <literal>WRITE</literal>
+ locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with
+ <literal role="stmt">INSERT</literal> combined with
+ <literal role="stmt">SELECT</literal>, consider switching to
+ <literal>MyISAM</literal> tables, which support concurrent
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">INSERT</literal> statements. (See
+ <xref linkend="concurrent-inserts"/>.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you mix inserts and deletes on the same table,
+ <literal role="stmt">INSERT DELAYED</literal> may be of
+ great help. See <xref linkend="insert-delayed"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with mixed
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">DELETE</literal> statements, the
+ <literal>LIMIT</literal> option to
+ <literal role="stmt">DELETE</literal> may help. See
+ <xref linkend="delete"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Using <literal>SQL_BUFFER_RESULT</literal> with
+ <literal role="stmt">SELECT</literal> statements can help to
+ make the duration of table locks shorter. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You could change the locking code in
+ <filename>mysys/thr_lock.c</filename> to use a single queue.
+ In this case, write locks and read locks would have the same
+ priority, which might help some applications.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Here are some tips concerning table locks in MySQL:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Concurrent users are not a problem if you do not mix updates
+ with selects that need to examine many rows in the same
+ table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can use <literal role="stmt">LOCK TABLES</literal> to
+ increase speed, because many updates within a single lock is
+ much faster than updating without locks. Splitting table
+ contents into separate tables may also help.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you encounter speed problems with table locks in MySQL,
+ you may be able to improve performance by converting some of
+ your tables to <literal>InnoDB</literal> or
+ <literal>BDB</literal> tables. See <xref linkend="innodb"/>,
+ and <xref linkend="bdb-storage-engine"/>.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ Lock contention can seriously degrade performance. The
+ MySQL Enterprise Monitor provides expert advice on
+ avoiding this problem. To subscribe, see
+ &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="concurrent-inserts">
+
+ <title>Concurrent Inserts</title>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ As of MySQL 3.23.7 (3.23.25 for Windows), the
+ <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no holes
+ in the data file (deleted rows in the middle), an
+ <literal role="stmt">INSERT</literal> statement can be executed
+ to add rows to the end of the table at the same time that
+ <literal role="stmt">SELECT</literal> statements are reading
+ rows from the table. If there are multiple
+ <literal role="stmt">INSERT</literal> statements, they are
+ queued and performed in sequence, concurrently with the
+ <literal role="stmt">SELECT</literal> statements. The results of
+ a concurrent <literal role="stmt">INSERT</literal> may not be
+ visible immediately.
+ </para>
+
+ <para>
+ Concurrent inserts are enabled by default, but can be disabled
+ by setting the
+ <literal role="sysvar">concurrent_insert</literal> system
+ variable to 0.
+ </para>
+
+ <para>
+ Under circumstances where concurrent inserts can be used, there
+ is seldom any need to use the <literal>DELAYED</literal>
+ modifier for <literal role="stmt">INSERT</literal> statements.
+ See <xref linkend="insert-delayed"/>.
+ </para>
+
+ <para>
+ If you are using the update log or binary log, concurrent
+ inserts are converted to normal inserts for <literal>CREATE ...
+ SELECT</literal> or
+ <literal role="stmt" condition="insert-select">INSERT ...
+ SELECT</literal> statements. This is done to ensure that you can
+ re-create an exact copy of your tables by applying the log
+ during a backup operation. See <xref linkend="binary-log"/>. In
+ addition, for those statements a read lock is placed on the
+ selected-from table such that inserts into that table are
+ blocked. The effect is that concurrent inserts for that table
+ must wait as well.
+ </para>
+
+ <para>
+ With <literal role="stmt" condition="load-data">LOAD DATA
+ INFILE</literal>, if you specify <literal>CONCURRENT</literal>
+ with a <literal>MyISAM</literal> table that satisfies the
+ condition for concurrent inserts (that is, it contains no free
+ blocks in the middle), other sessions can retrieve data from the
+ table while <literal role="stmt">LOAD DATA</literal> is
+ executing. Use of the <literal>CONCURRENT</literal> option
+ affects the performance of <literal role="stmt">LOAD
+ DATA</literal> a bit, even if no other session is using the
+ table at the same time.
+ </para>
+
+ <para>
+ If you specify <literal>HIGH_PRIORITY</literal>, it overrides
+ the effect of the
+ <option role="mysqld">--low-priority-updates</option> option if
+ the server was started with that option. It also causes
+ concurrent inserts not to be used.
+ </para>
+
+ <para>
+ For <literal role="stmt" condition="lock-tables">LOCK
+ TABLE</literal>, the difference between <literal>READ
+ LOCAL</literal> and <literal>READ</literal> is that
+ <literal>READ LOCAL</literal> permits nonconflicting
+ <literal role="stmt">INSERT</literal> statements (concurrent
+ inserts) to execute while the lock is held. However, this cannot
+ be used if you are going to manipulate the database using
+ processes external to the server while you hold the lock.
+ </para>
+
+ </section>
+
+ <section id="external-locking">
+
+ <title>External Locking</title>
+
+ <indexterm>
+ <primary>external locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>external</secondary>
+ </indexterm>
+
+ <para>
+ External locking is the use of file system locking to manage
+ contention for database tables by multiple processes. External
+ locking is used in situations where a single process such as the
+ MySQL server cannot be assumed to be the only process that
+ requires access to tables. Here are some examples:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ If you run multiple servers that use the same database
+ directory (not recommended), each server must have external
+ locking enabled.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you use <command>myisamchk</command> to perform table
+ maintenance operations on <literal>MyISAM</literal> tables,
+ you must either ensure that the server is not running, or
+ that the server has external locking enabled so that it
+ locks table files as necessary to coordinate with
+ <command>myisamchk</command> for access to the tables. The
+ same is true for use of <command>myisampack</command> to
+ pack <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ If the server is run with external locking enabled, you can
+ use <command>myisamchk</command> at any time for read
+ operations such a checking tables. In this case, if the
+ server tries to update a table that
+ <command>myisamchk</command> is using, the server will wait
+ for <command>myisamchk</command> to finish before it
+ continues.
+ </para>
+
+ <para>
+ If you use <command>myisamchk</command> for write operations
+ such as repairing or optimizing tables, or if you use
+ <command>myisampack</command> to pack tables, you
+ <emphasis>must</emphasis> always ensure that the
+ <command>mysqld</command> server is not using the table. If
+ you don't stop <command>mysqld</command>, you should at
+ least do a <command>mysqladmin flush-tables</command> before
+ you run <command>myisamchk</command>. Your tables
+ <emphasis>may become corrupted</emphasis> if the server and
+ <command>myisamchk</command> access the tables
+ simultaneously.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With external locking in effect, each process that requires
+ access to a table acquires a file system lock for the table
+ files before proceeding to access the table. If all necessary
+ locks cannot be acquired, the process is blocked from accessing
+ the table until the locks can be obtained (after the process
+ that currently holds the locks releases them).
+ </para>
+
+ <para>
+ External locking affects server performance because the server
+ must sometimes wait for other processes before it can access
+ tables.
+ </para>
+
+ <para>
+ External locking is unnecessary if you run a single server to
+ access a given data directory (which is the usual case) and if
+ no other programs such as <command>myisamchk</command> need to
+ modify tables while the server is running. If you only
+ <emphasis>read</emphasis> tables with other programs, external
+ locking is not required, although <command>myisamchk</command>
+ might report warnings if the server changes tables while
+ <command>myisamchk</command> is reading them.
+ </para>
+
+ <para>
+ With external locking disabled, to use
+ <command>myisamchk</command>, you must either stop the server
+ while <command>myisamchk</command> executes or else lock and
+ flush the tables before running <command>myisamchk</command>.
+ (See <xref linkend="system-optimization"/>.) To avoid this
+ requirement as of MySQL 3.23, use the <literal role="stmt">CHECK
+ TABLE</literal> and <literal role="stmt">REPAIR TABLE</literal>
+ statements to check and repair <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ For <command>mysqld</command>, external locking is controlled by
+ the value of the
+ <literal role="sysvar">skip_external_locking</literal> system
+ variable. (Before MySQL 4.0.3, this variable is named
+ <literal>skip_locking</literal>.) When this variable is enabled,
+ external locking is disabled, and vice versa. From MySQL 4.0 on,
+ external locking is disabled by default. Before MySQL 4.0,
+ external locking is enabled by default on Linux or when MySQL is
+ configured to use MIT-pthreads.
+ </para>
+
+ <para>
+ Use of external locking can be controlled at server startup by
+ using the <option role="mysqld">--external-locking</option> or
+ <option role="mysqld">--skip-external-locking</option> option.
+ (Before MySQL 4.0.3, these options are named
+ <option>--enable-locking</option> and
+ <option>--skip-locking</option>.)
+ </para>
+
+ <para>
+ If you do use external locking option to enable updates to
+ <literal>MyISAM</literal> tables from many MySQL processes, you
+ must ensure that the following conditions are satisfied:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ You should not use the query cache for queries that use
+ tables that are updated by another process.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You should not start the server with the
+ <option role="mysqld">--delay-key-write=ALL</option> option
+ or use the <literal>DELAY_KEY_WRITE=1</literal> table option
+ for any shared tables. Otherwise, index corruption can
+ occur.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The easiest way to satisfy these conditions is to always use
+ <option role="mysqld">--external-locking</option> together with
+ <option role="mysqld">--delay-key-write=OFF</option> and
+ <option role="sysvar">--query-cache-size=0</option>. (This is
+ not done by default because in many setups it is useful to have
+ a mixture of the preceding options.)
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="optimizing-database-structure">
+
+ <title>Optimizing Database Structure</title>
+
+ <section id="data-size">
+
+ <title>Make Your Data as Small as Possible</title>
+
+ <indexterm>
+ <primary>data</primary>
+ <secondary>size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>reducing</primary>
+ <secondary>data size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>storage space</primary>
+ <secondary>minimizing</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>tables</primary>
+ <secondary>improving performance</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>performance</primary>
+ <secondary>improving</secondary>
+ </indexterm>
+
+ <para>
+ One of the most basic optimizations is to design your tables to
+ take as little space on the disk as possible. This can result in
+ huge improvements because disk reads are faster, and smaller
+ tables normally require less main memory while their contents
+ are being actively processed during query execution. Indexing
+ also is a lesser resource burden if done on smaller columns.
+ </para>
+
+ <para>
+ MySQL supports many different storage engines (table types) and
+ row formats. For each table, you can decide which storage and
+ indexing method to use. Choosing the proper table format for
+ your application may give you a big performance gain. See
+ <xref linkend="storage-engines"/>.
+ </para>
+
+ <para>
+ You can get better performance for a table and minimize storage
+ space by using the techniques listed here:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Use the most efficient (smallest) data types possible. MySQL
+ has many specialized types that save disk space and memory.
+ For example, use the smaller integer types if possible to
+ get smaller tables. <literal role="type">MEDIUMINT</literal>
+ is often a better choice than
+ <literal role="type">INT</literal> because a
+ <literal role="type">MEDIUMINT</literal> column uses 25%
+ less space.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Declare columns to be <literal>NOT NULL</literal> if
+ possible. It makes everything faster and you save one bit
+ per column. If you really need <literal>NULL</literal> in
+ your application, you should definitely use it. Just avoid
+ having it on all columns by default.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For <literal>MyISAM</literal> tables, if you do not have any
+ variable-length columns
+ (<literal role="type">VARCHAR</literal>,
+ <literal role="type">TEXT</literal>, or
+ <literal role="type">BLOB</literal> columns), a fixed-size
+ row format is used. This is faster but unfortunately may
+ waste some space. See
+ <xref linkend="myisam-table-formats"/>. You can hint that
+ you want to have fixed length rows even if you have
+ <literal role="type">VARCHAR</literal> columns with the
+ <literal role="stmt">CREATE TABLE</literal> option
+ <literal>ROW_FORMAT=FIXED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The primary index of a table should be as short as possible.
+ This makes identification of each row easy and efficient.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create only the indexes that you really need. Indexes are
+ good for retrieval but bad when you need to store data
+ quickly. If you access a table mostly by searching on a
+ combination of columns, create an index on them. The first
+ part of the index should be the column most used. If you
+ <emphasis>always</emphasis> use many columns when selecting
+ from the table, the first column in the index should be the
+ one with the most duplicates to obtain better compression of
+ the index.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If it is very likely that a string column has a unique
+ prefix on the first number of characters, it is better to
+ index only this prefix, using MySQL's support for creating
+ an index on the leftmost part of the column (see
+ <xref linkend="create-index"/>). Shorter indexes are faster,
+ not only because they require less disk space, but because
+ they also give you more hits in the index cache, and thus
+ fewer disk seeks. See <xref linkend="server-parameters"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ In some circumstances, it can be beneficial to split into
+ two a table that is scanned very often. This is especially
+ true if it is a dynamic-format table and it is possible to
+ use a smaller static format table that can be used to find
+ the relevant rows when scanning the table.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
<section id="table-cache">
<title>How MySQL Opens and Closes Tables</title>
Modified: trunk/refman-4.1/renamed-nodes.txt
===================================================================
--- trunk/refman-4.1/renamed-nodes.txt 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-4.1/renamed-nodes.txt 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 0; 614 bytes
@@ -38,6 +38,7 @@
drop-function drop-function-udf 2009-08-01
eiffel apis-eiffel 2009-09-01
group-by-hidden-fields group-by-hidden-columns 2010-01-01
+indexes column-indexes 2011-07-14
innodb-and-autocommit innodb-transaction-model 2009-11-24
innodb-consistent-read-example innodb-consistent-read 2010-03-10
innodb-general-monitor innodb-monitors 2010-11-05
Modified: trunk/refman-4.1/sql-syntax-data-definition.xml
===================================================================
--- trunk/refman-4.1/sql-syntax-data-definition.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-4.1/sql-syntax-data-definition.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 663 bytes
@@ -2241,7 +2241,7 @@
<literal role="type">VARBINARY</literal>, and
<literal role="type">BLOB</literal> columns. Indexing only a
prefix of column values like this can make the index file much
- smaller. See <xref linkend="indexes"/>.
+ smaller. See <xref linkend="column-indexes"/>.
</para>
<indexterm>
Modified: trunk/refman-5.0/data-types.xml
===================================================================
--- trunk/refman-5.0/data-types.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.0/data-types.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 594 bytes
@@ -4922,7 +4922,7 @@
specify an index prefix length. For
<literal role="type">CHAR</literal> and
<literal role="type">VARCHAR</literal>, a prefix length is
- optional. See <xref linkend="indexes"/>.
+ optional. See <xref linkend="column-indexes"/>.
</para>
</listitem>
Modified: trunk/refman-5.0/optimization.xml
===================================================================
--- trunk/refman-5.0/optimization.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.0/optimization.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 3, Lines Added: 1147, Lines Deleted: 1141; 84433 bytes
@@ -7609,1149 +7609,12 @@
</section>
- <section id="locking-issues">
+ <section id="optimization-indexes">
- <title>Locking Issues</title>
+ <title>Optimization and Indexes</title>
- <para>
- MySQL manages contention for table contents using locking:
- </para>
+ <section id="column-indexes">
- <itemizedlist>
-
- <listitem>
- <para>
- Internal locking is performed within the MySQL server itself
- to manage contention for table contents by multiple threads.
- This type of locking is internal because it is performed
- entirely by the server and involves no other programs. See
- <xref linkend="internal-locking"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- External locking occurs when the server and other programs
- lock table files to coordinate among themselves which program
- can access the tables at which time. See
- <xref linkend="external-locking"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <section id="internal-locking">
-
- <title>Internal Locking Methods</title>
-
- <indexterm>
- <primary>internal locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>internal</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking methods</primary>
- </indexterm>
-
- <indexterm>
- <primary>methods</primary>
- <secondary>locking</secondary>
- </indexterm>
-
- <indexterm>
- <primary>row-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>page-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>table-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>row-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>page-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>table-level</secondary>
- </indexterm>
-
- <para>
- This section discusses internal locking; that is, locking
- performed within the MySQL server itself to manage contention
- for table contents by multiple sessions. This type of locking is
- internal because it is performed entirely by the server and
- involves no other programs. External locking occurs when the
- server and other programs lock table files to coordinate among
- themselves which program can access the tables at which time.
- See <xref linkend="external-locking"/>.
- </para>
-
- <para>
- MySQL uses table-level locking for <literal>MyISAM</literal>,
- <literal>MEMORY</literal> and <literal>MERGE</literal> tables,
- page-level locking for <literal>BDB</literal> tables, and
- row-level locking for <literal>InnoDB</literal> tables.
- </para>
-
- <para>
- In many cases, you can make an educated guess about which
- locking type is best for an application, but generally it is
- difficult to say that a given lock type is better than another.
- Everything depends on the application and different parts of an
- application may require different lock types.
- </para>
-
- <para>
- To decide whether you want to use a storage engine with
- row-level locking, you should look at what your application does
- and what mix of select and update statements it uses. For
- example, most Web applications perform many selects, relatively
- few deletes, updates based mainly on key values, and inserts
- into a few specific tables. The base MySQL
- <literal>MyISAM</literal> setup is very well tuned for this.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- The MySQL Enterprise Monitor provides expert advice on when to
- use table-level locking and when to use row-level locking. To
- subscribe, see &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
-
- <para>
- Table locking in MySQL is deadlock-free for storage engines that
- use table-level locking. Deadlock avoidance is managed by always
- requesting all needed locks at once at the beginning of a query
- and always locking the tables in the same order.
- </para>
-
- <para>
- MySQL grants table write locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no locks on the table, put a write lock on it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the write lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- MySQL grants table read locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no write locks on the table, put a read lock on
- it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the read lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- Table updates are given higher priority than table retrievals.
- Therefore, when a lock is released, the lock is made available
- to the requests in the write lock queue and then to the requests
- in the read lock queue. This ensures that updates to a table are
- not <quote>starved</quote> even if there is heavy
- <literal role="stmt">SELECT</literal> activity for the table.
- However, if you have many updates for a table,
- <literal role="stmt">SELECT</literal> statements wait until
- there are no more updates.
- </para>
-
- <para>
- For information on altering the priority of reads and writes,
- see <xref linkend="table-locking"/>.
- </para>
-
- <para>
- You can analyze the table lock contention on your system by
- checking the
- <literal role="statvar">Table_locks_immediate</literal> and
- <literal role="statvar">Table_locks_waited</literal> status
- variables, which indicate the number of times that requests for
- table locks could be granted immediately and the number that had
- to wait, respectively:
- </para>
-
-<programlisting>
-mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
-+-----------------------+---------+
-| Variable_name | Value |
-+-----------------------+---------+
-| Table_locks_immediate | 1151552 |
-| Table_locks_waited | 15324 |
-+-----------------------+---------+
-</programlisting>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no free
- blocks in the middle of the data file, rows are always inserted
- at the end of the data file. In this case, you can freely mix
- concurrent <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> statements for a
- <literal>MyISAM</literal> table without locks. That is, you can
- insert rows into a <literal>MyISAM</literal> table at the same
- time other clients are reading from it. Holes can result from
- rows having been deleted from or updated in the middle of the
- table. If there are holes, concurrent inserts are disabled but
- are enabled again automatically when all holes have been filled
- with new data. This behavior is altered by the
- <literal role="sysvar">concurrent_insert</literal> system
- variable. See <xref linkend="concurrent-inserts"/>.
- </para>
-
- <para>
- If you acquire a table lock explicitly with
- <literal role="stmt">LOCK TABLES</literal>, you can request a
- <literal>READ LOCAL</literal> lock rather than a
- <literal>READ</literal> lock to enable other sessions to perform
- concurrent inserts while you have the table locked.
- </para>
-
- <para>
- To perform many <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> operations on a table
- <literal>real_table</literal> when concurrent inserts are not
- possible, you can insert rows into a temporary table
- <literal>temp_table</literal> and update the real table with the
- rows from the temporary table periodically. This can be done
- with the following code:
- </para>
-
-<programlisting>
-mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
-mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
-mysql> <userinput>DELETE FROM temp_table;</userinput>
-mysql> <userinput>UNLOCK TABLES;</userinput>
-</programlisting>
-
- <para>
- <literal>InnoDB</literal> uses row locks and
- <literal>BDB</literal> uses page locks. Deadlocks are possible
- for these storage engines because they automatically acquire
- locks during the processing of SQL statements, not at the start
- of the transaction.
- </para>
-
- <para>
- Advantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Fewer lock conflicts when different sessions access
- different rows
- </para>
- </listitem>
-
- <listitem>
- <para>
- Fewer changes for rollbacks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Possible to lock a single row for a long time
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Disadvantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Requires more memory than page-level or table-level locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than page-level or table-level locks when used on a
- large part of the table because you must acquire many more
- locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than other locks if you often do <literal>GROUP
- BY</literal> operations on a large part of the data or if
- you must scan the entire table frequently
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Generally, table locks are superior to page-level or row-level
- locks in the following cases:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Most statements for the table are reads
- </para>
- </listitem>
-
- <listitem>
- <para>
- Statements for the table are a mix of reads and writes,
- where writes are updates or deletes for a single row that
- can be fetched with one key read:
- </para>
-
-<programlisting>
-UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-</programlisting>
- </listitem>
-
- <listitem>
- <para>
- <literal role="stmt">SELECT</literal> combined with
- concurrent <literal role="stmt">INSERT</literal> statements,
- and very few <literal role="stmt">UPDATE</literal> or
- <literal role="stmt">DELETE</literal> statements
- </para>
- </listitem>
-
- <listitem>
- <para>
- Many scans or <literal>GROUP BY</literal> operations on the
- entire table without any writers
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With higher-level locks, you can more easily tune applications
- by supporting locks of different types, because the lock
- overhead is less than for row-level locks.
- </para>
-
- <para>
- Options other than row-level or page-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Versioning (such as that used in MySQL for concurrent
- inserts) where it is possible to have one writer at the same
- time as many readers. This means that the database or table
- supports different views for the data depending on when
- access begins. Other common terms for this are <quote>time
- travel,</quote> <quote>copy on write,</quote> or <quote>copy
- on demand.</quote>
- </para>
- </listitem>
-
- <listitem>
- <para>
- Copy on demand is in many cases superior to page-level or
- row-level locking. However, in the worst case, it can use
- much more memory than using normal locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Instead of using row-level locks, you can employ
- application-level locks, such as those provided by
- <literal role="func">GET_LOCK()</literal> and
- <literal role="func">RELEASE_LOCK()</literal> in MySQL.
- These are advisory locks, so they work only with
- applications that cooperate with each other. See
- <xref linkend="miscellaneous-functions"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="table-locking">
-
- <title>Table Locking Issues</title>
-
- <indexterm>
- <primary>problems</primary>
- <secondary>table locking</secondary>
- </indexterm>
-
- <para>
- To achieve a very high lock speed, MySQL uses table locking
- (instead of page, row, or column locking) for all storage
- engines except <literal>InnoDB</literal>,
- <literal>BDB</literal>, and
- <literal role="se">NDBCLUSTER</literal>.
- </para>
-
- <para>
- For <literal>InnoDB</literal> and <literal>BDB</literal> tables,
- MySQL uses table locking only if you explicitly lock the table
- with <literal role="stmt">LOCK TABLES</literal>. For these
- storage engines, avoid using <literal role="stmt">LOCK
- TABLES</literal> at all, because <literal>InnoDB</literal> uses
- automatic row-level locking and <literal>BDB</literal> uses
- page-level locking to ensure transaction isolation.
- </para>
-
- <para>
- For large tables, table locking is often better than row
- locking, but there are some disadvantages:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Table locking enables many sessions to read from a table at
- the same time, but if a session wants to write to a table,
- it must first get exclusive access. During the update, all
- other sessions that want to access this particular table
- must wait until the update is done.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Table locking causes problems in cases such as when a
- session is waiting because the disk is full and free space
- needs to become available before the session can proceed. In
- this case, all sessions that want to access the problem
- table are also put in a waiting state until more disk space
- is made available.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Table locking is also disadvantageous under the following
- scenario:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A session issues a <literal role="stmt">SELECT</literal>
- that takes a long time to run.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session then issues an
- <literal role="stmt">UPDATE</literal> on the same table.
- This session waits until the
- <literal role="stmt">SELECT</literal> is finished.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session issues another
- <literal role="stmt">SELECT</literal> statement on the same
- table. Because <literal role="stmt">UPDATE</literal> has
- higher priority than <literal role="stmt">SELECT</literal>,
- this <literal role="stmt">SELECT</literal> waits for the
- <literal role="stmt">UPDATE</literal> to finish,
- <emphasis>after</emphasis> waiting for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following items describe some ways to avoid or reduce
- contention caused by table locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Try to get the <literal role="stmt">SELECT</literal>
- statements to run faster so that they lock tables for a
- shorter time. You might have to create some summary tables
- to do this.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with
- <option role="mysqld">--low-priority-updates</option>. For
- storage engines that use only table-level locking (such as
- <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
- <literal>MERGE</literal>), this gives all statements that
- update (modify) a table lower priority than
- <literal role="stmt">SELECT</literal> statements. In this
- case, the second <literal role="stmt">SELECT</literal>
- statement in the preceding scenario would execute before the
- <literal role="stmt">UPDATE</literal> statement, and would
- not need to wait for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To specify that all updates issued in a specific connection
- should be done with low priority, set the
- <literal role="sysvar">low_priority_updates</literal> server
- system variable equal to 1.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">INSERT</literal>,
- <literal role="stmt">UPDATE</literal>, or
- <literal role="stmt">DELETE</literal> statement lower
- priority, use the <literal>LOW_PRIORITY</literal> attribute.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">SELECT</literal>
- statement higher priority, use the
- <literal>HIGH_PRIORITY</literal> attribute. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with a low value for the
- <literal role="sysvar">max_write_lock_count</literal> system
- variable to force MySQL to temporarily elevate the priority
- of all <literal role="stmt">SELECT</literal> statements that
- are waiting for a table after a specific number of inserts
- to the table occur. This permits <literal>READ</literal>
- locks after a certain number of <literal>WRITE</literal>
- locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with
- <literal role="stmt">INSERT</literal> combined with
- <literal role="stmt">SELECT</literal>, consider switching to
- <literal>MyISAM</literal> tables, which support concurrent
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">INSERT</literal> statements. (See
- <xref linkend="concurrent-inserts"/>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you mix inserts and deletes on the same table,
- <literal role="stmt">INSERT DELAYED</literal> may be of
- great help. See <xref linkend="insert-delayed"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with mixed
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">DELETE</literal> statements, the
- <literal>LIMIT</literal> option to
- <literal role="stmt">DELETE</literal> may help. See
- <xref linkend="delete"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Using <literal>SQL_BUFFER_RESULT</literal> with
- <literal role="stmt">SELECT</literal> statements can help to
- make the duration of table locks shorter. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You could change the locking code in
- <filename>mysys/thr_lock.c</filename> to use a single queue.
- In this case, write locks and read locks would have the same
- priority, which might help some applications.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Here are some tips concerning table locks in MySQL:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Concurrent users are not a problem if you do not mix updates
- with selects that need to examine many rows in the same
- table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can use <literal role="stmt">LOCK TABLES</literal> to
- increase speed, because many updates within a single lock is
- much faster than updating without locks. Splitting table
- contents into separate tables may also help.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you encounter speed problems with table locks in MySQL,
- you may be able to improve performance by converting some of
- your tables to <literal>InnoDB</literal> or
- <literal>BDB</literal> tables. See <xref linkend="innodb"/>,
- and <xref linkend="bdb-storage-engine"/>.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- Lock contention can seriously degrade performance. The
- MySQL Enterprise Monitor provides expert advice on
- avoiding this problem. To subscribe, see
- &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="concurrent-inserts">
-
- <title>Concurrent Inserts</title>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no holes
- in the data file (deleted rows in the middle), an
- <literal role="stmt">INSERT</literal> statement can be executed
- to add rows to the end of the table at the same time that
- <literal role="stmt">SELECT</literal> statements are reading
- rows from the table. If there are multiple
- <literal role="stmt">INSERT</literal> statements, they are
- queued and performed in sequence, concurrently with the
- <literal role="stmt">SELECT</literal> statements. The results of
- a concurrent <literal role="stmt">INSERT</literal> may not be
- visible immediately.
- </para>
-
- <para>
- The <literal role="sysvar">concurrent_insert</literal> system
- variable can be set to modify the concurrent-insert processing.
- By default, the variable is set to 1 and concurrent inserts are
- handled as just described. If
- <literal role="sysvar">concurrent_insert</literal> is set to 0,
- concurrent inserts are disabled. If the variable is set to 2,
- concurrent inserts at the end of the table are allowed even for
- tables that have deleted rows. See also the description of the
- <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
- system variable.
- </para>
-
- <para>
- Under circumstances where concurrent inserts can be used, there
- is seldom any need to use the <literal>DELAYED</literal>
- modifier for <literal role="stmt">INSERT</literal> statements.
- See <xref linkend="insert-delayed"/>.
- </para>
-
- <para>
- If you are using the binary log, concurrent inserts are
- converted to normal inserts for <literal>CREATE ...
- SELECT</literal> or
- <literal role="stmt" condition="insert-select">INSERT ...
- SELECT</literal> statements. This is done to ensure that you can
- re-create an exact copy of your tables by applying the log
- during a backup operation. See <xref linkend="binary-log"/>. In
- addition, for those statements a read lock is placed on the
- selected-from table such that inserts into that table are
- blocked. The effect is that concurrent inserts for that table
- must wait as well.
- </para>
-
- <para>
- With <literal role="stmt" condition="load-data">LOAD DATA
- INFILE</literal>, if you specify <literal>CONCURRENT</literal>
- with a <literal>MyISAM</literal> table that satisfies the
- condition for concurrent inserts (that is, it contains no free
- blocks in the middle), other sessions can retrieve data from the
- table while <literal role="stmt">LOAD DATA</literal> is
- executing. Use of the <literal>CONCURRENT</literal> option
- affects the performance of <literal role="stmt">LOAD
- DATA</literal> a bit, even if no other session is using the
- table at the same time.
- </para>
-
- <para>
- If you specify <literal>HIGH_PRIORITY</literal>, it overrides
- the effect of the
- <option role="mysqld">--low-priority-updates</option> option if
- the server was started with that option. It also causes
- concurrent inserts not to be used.
- </para>
-
- <para>
- For <literal role="stmt" condition="lock-tables">LOCK
- TABLE</literal>, the difference between <literal>READ
- LOCAL</literal> and <literal>READ</literal> is that
- <literal>READ LOCAL</literal> permits nonconflicting
- <literal role="stmt">INSERT</literal> statements (concurrent
- inserts) to execute while the lock is held. However, this cannot
- be used if you are going to manipulate the database using
- processes external to the server while you hold the lock.
- </para>
-
- </section>
-
- <section id="external-locking">
-
- <title>External Locking</title>
-
- <indexterm>
- <primary>external locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>external</secondary>
- </indexterm>
-
- <para>
- External locking is the use of file system locking to manage
- contention for database tables by multiple processes. External
- locking is used in situations where a single process such as the
- MySQL server cannot be assumed to be the only process that
- requires access to tables. Here are some examples:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- If you run multiple servers that use the same database
- directory (not recommended), each server must have external
- locking enabled.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you use <command>myisamchk</command> to perform table
- maintenance operations on <literal>MyISAM</literal> tables,
- you must either ensure that the server is not running, or
- that the server has external locking enabled so that it
- locks table files as necessary to coordinate with
- <command>myisamchk</command> for access to the tables. The
- same is true for use of <command>myisampack</command> to
- pack <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- If the server is run with external locking enabled, you can
- use <command>myisamchk</command> at any time for read
- operations such a checking tables. In this case, if the
- server tries to update a table that
- <command>myisamchk</command> is using, the server will wait
- for <command>myisamchk</command> to finish before it
- continues.
- </para>
-
- <para>
- If you use <command>myisamchk</command> for write operations
- such as repairing or optimizing tables, or if you use
- <command>myisampack</command> to pack tables, you
- <emphasis>must</emphasis> always ensure that the
- <command>mysqld</command> server is not using the table. If
- you don't stop <command>mysqld</command>, you should at
- least do a <command>mysqladmin flush-tables</command> before
- you run <command>myisamchk</command>. Your tables
- <emphasis>may become corrupted</emphasis> if the server and
- <command>myisamchk</command> access the tables
- simultaneously.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With external locking in effect, each process that requires
- access to a table acquires a file system lock for the table
- files before proceeding to access the table. If all necessary
- locks cannot be acquired, the process is blocked from accessing
- the table until the locks can be obtained (after the process
- that currently holds the locks releases them).
- </para>
-
- <para>
- External locking affects server performance because the server
- must sometimes wait for other processes before it can access
- tables.
- </para>
-
- <para>
- External locking is unnecessary if you run a single server to
- access a given data directory (which is the usual case) and if
- no other programs such as <command>myisamchk</command> need to
- modify tables while the server is running. If you only
- <emphasis>read</emphasis> tables with other programs, external
- locking is not required, although <command>myisamchk</command>
- might report warnings if the server changes tables while
- <command>myisamchk</command> is reading them.
- </para>
-
- <para>
- With external locking disabled, to use
- <command>myisamchk</command>, you must either stop the server
- while <command>myisamchk</command> executes or else lock and
- flush the tables before running <command>myisamchk</command>.
- (See <xref linkend="system-optimization"/>.) To avoid this
- requirement, use the <literal role="stmt">CHECK TABLE</literal>
- and <literal role="stmt">REPAIR TABLE</literal> statements to
- check and repair <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- For <command>mysqld</command>, external locking is controlled by
- the value of the
- <literal role="sysvar">skip_external_locking</literal> system
- variable. When this variable is enabled, external locking is
- disabled, and vice versa. From MySQL 4.0 on, external locking is
- disabled by default. Before MySQL 4.0, external locking is
- enabled by default on Linux or when MySQL is configured to use
- MIT-pthreads.
- </para>
-
- <para>
- Use of external locking can be controlled at server startup by
- using the <option role="mysqld">--external-locking</option> or
- <option role="mysqld">--skip-external-locking</option> option.
- </para>
-
- <para>
- If you do use external locking option to enable updates to
- <literal>MyISAM</literal> tables from many MySQL processes, you
- must ensure that the following conditions are satisfied:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- You should not use the query cache for queries that use
- tables that are updated by another process.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You should not start the server with the
- <option role="mysqld">--delay-key-write=ALL</option> option
- or use the <literal>DELAY_KEY_WRITE=1</literal> table option
- for any shared tables. Otherwise, index corruption can
- occur.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The easiest way to satisfy these conditions is to always use
- <option role="mysqld">--external-locking</option> together with
- <option role="mysqld">--delay-key-write=OFF</option> and
- <option role="sysvar">--query-cache-size=0</option>. (This is
- not done by default because in many setups it is useful to have
- a mixture of the preceding options.)
- </para>
-
- </section>
-
- </section>
-
- <section id="optimizing-database-structure">
-
- <title>Optimizing Database Structure</title>
-
- <section id="data-size">
-
- <title>Make Your Data as Small as Possible</title>
-
- <indexterm>
- <primary>data</primary>
- <secondary>size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>reducing</primary>
- <secondary>data size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>storage space</primary>
- <secondary>minimizing</secondary>
- </indexterm>
-
- <indexterm>
- <primary>tables</primary>
- <secondary>improving performance</secondary>
- </indexterm>
-
- <indexterm>
- <primary>performance</primary>
- <secondary>improving</secondary>
- </indexterm>
-
- <para>
- One of the most basic optimizations is to design your tables to
- take as little space on the disk as possible. This can result in
- huge improvements because disk reads are faster, and smaller
- tables normally require less main memory while their contents
- are being actively processed during query execution. Indexing
- also is a lesser resource burden if done on smaller columns.
- </para>
-
- <para>
- MySQL supports many different storage engines (table types) and
- row formats. For each table, you can decide which storage and
- indexing method to use. Choosing the proper table format for
- your application may give you a big performance gain. See
- <xref linkend="storage-engines"/>.
- </para>
-
- <para>
- You can get better performance for a table and minimize storage
- space by using the techniques listed here:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Use the most efficient (smallest) data types possible. MySQL
- has many specialized types that save disk space and memory.
- For example, use the smaller integer types if possible to
- get smaller tables. <literal role="type">MEDIUMINT</literal>
- is often a better choice than
- <literal role="type">INT</literal> because a
- <literal role="type">MEDIUMINT</literal> column uses 25%
- less space.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Declare columns to be <literal>NOT NULL</literal> if
- possible. It makes everything faster and you save one bit
- per column. If you really need <literal>NULL</literal> in
- your application, you should definitely use it. Just avoid
- having it on all columns by default.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For <literal>MyISAM</literal> tables, if you do not have any
- variable-length columns
- (<literal role="type">VARCHAR</literal>,
- <literal role="type">TEXT</literal>, or
- <literal role="type">BLOB</literal> columns), a fixed-size
- row format is used. This is faster but unfortunately may
- waste some space. See
- <xref linkend="myisam-table-formats"/>. You can hint that
- you want to have fixed length rows even if you have
- <literal role="type">VARCHAR</literal> columns with the
- <literal role="stmt">CREATE TABLE</literal> option
- <literal>ROW_FORMAT=FIXED</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Starting with MySQL 5.0.3, <literal>InnoDB</literal> tables
- use a more compact storage format. In earlier versions of
- MySQL, <literal>InnoDB</literal> rows contain some redundant
- information, such as the number of columns and the length of
- each column, even for fixed-size columns. By default, tables
- are created in the compact format
- (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
- downgrade to older versions of MySQL, you can request the
- old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
- </para>
-
- <para>
- The presence of the compact row format decreases row storage
- space by about 20% at the cost of increasing CPU use for
- some operations. If your workload is a typical one that is
- limited by cache hit rates and disk speed it is likely to be
- faster. If it is a rare case that is limited by CPU speed,
- it might be slower.
- </para>
-
- <para>
- The compact <literal>InnoDB</literal> format also changes
- how <literal role="type">CHAR</literal> columns containing
- UTF-8 data are stored. With
- <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
- <literal>CHAR(<replaceable>N</replaceable>)</literal>
- occupies 3 × <replaceable>N</replaceable> bytes, given
- that the maximum length of a UTF-8 encoded character is
- three bytes. Many languages can be written primarily using
- single-byte UTF-8 characters, so a fixed storage length
- often wastes space. With
- <literal>ROW_FORMAT=COMPACT</literal> format,
- <literal>InnoDB</literal> allocates a variable amount of
- storage in the range from <replaceable>N</replaceable> to 3
- × <replaceable>N</replaceable> bytes for these columns
- by stripping trailing spaces if necessary. The minimum
- storage length is kept as <replaceable>N</replaceable> bytes
- to facilitate in-place updates in typical cases.
- </para>
- </listitem>
-
- <listitem>
- <para>
- The primary index of a table should be as short as possible.
- This makes identification of each row easy and efficient.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Create only the indexes that you really need. Indexes are
- good for retrieval but bad when you need to store data
- quickly. If you access a table mostly by searching on a
- combination of columns, create an index on them. The first
- part of the index should be the column most used. If you
- <emphasis>always</emphasis> use many columns when selecting
- from the table, the first column in the index should be the
- one with the most duplicates to obtain better compression of
- the index.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If it is very likely that a string column has a unique
- prefix on the first number of characters, it is better to
- index only this prefix, using MySQL's support for creating
- an index on the leftmost part of the column (see
- <xref linkend="create-index"/>). Shorter indexes are faster,
- not only because they require less disk space, but because
- they also give you more hits in the index cache, and thus
- fewer disk seeks. See <xref linkend="server-parameters"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- In some circumstances, it can be beneficial to split into
- two a table that is scanned very often. This is especially
- true if it is a dynamic-format table and it is possible to
- use a smaller static format table that can be used to find
- the relevant rows when scanning the table.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="indexes">
-
<title>Column Indexes</title>
<indexterm>
@@ -8882,7 +7745,7 @@
MySQL can create composite indexes (that is, indexes on multiple
columns). An index may consist of up to 16 columns. For certain
data types, you can index a prefix of the column (see
- <xref linkend="indexes"/>).
+ <xref linkend="column-indexes"/>).
</para>
<para>
@@ -10393,6 +9256,1149 @@
</section>
+ </section>
+
+ <section id="locking-issues">
+
+ <title>Locking Issues</title>
+
+ <para>
+ MySQL manages contention for table contents using locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Internal locking is performed within the MySQL server itself
+ to manage contention for table contents by multiple threads.
+ This type of locking is internal because it is performed
+ entirely by the server and involves no other programs. See
+ <xref linkend="internal-locking"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ External locking occurs when the server and other programs
+ lock table files to coordinate among themselves which program
+ can access the tables at which time. See
+ <xref linkend="external-locking"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <section id="internal-locking">
+
+ <title>Internal Locking Methods</title>
+
+ <indexterm>
+ <primary>internal locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>internal</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking methods</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>methods</primary>
+ <secondary>locking</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>page-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>table-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>row-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>page-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>table-level</secondary>
+ </indexterm>
+
+ <para>
+ This section discusses internal locking; that is, locking
+ performed within the MySQL server itself to manage contention
+ for table contents by multiple sessions. This type of locking is
+ internal because it is performed entirely by the server and
+ involves no other programs. External locking occurs when the
+ server and other programs lock table files to coordinate among
+ themselves which program can access the tables at which time.
+ See <xref linkend="external-locking"/>.
+ </para>
+
+ <para>
+ MySQL uses table-level locking for <literal>MyISAM</literal>,
+ <literal>MEMORY</literal> and <literal>MERGE</literal> tables,
+ page-level locking for <literal>BDB</literal> tables, and
+ row-level locking for <literal>InnoDB</literal> tables.
+ </para>
+
+ <para>
+ In many cases, you can make an educated guess about which
+ locking type is best for an application, but generally it is
+ difficult to say that a given lock type is better than another.
+ Everything depends on the application and different parts of an
+ application may require different lock types.
+ </para>
+
+ <para>
+ To decide whether you want to use a storage engine with
+ row-level locking, you should look at what your application does
+ and what mix of select and update statements it uses. For
+ example, most Web applications perform many selects, relatively
+ few deletes, updates based mainly on key values, and inserts
+ into a few specific tables. The base MySQL
+ <literal>MyISAM</literal> setup is very well tuned for this.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ The MySQL Enterprise Monitor provides expert advice on when to
+ use table-level locking and when to use row-level locking. To
+ subscribe, see &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+
+ <para>
+ Table locking in MySQL is deadlock-free for storage engines that
+ use table-level locking. Deadlock avoidance is managed by always
+ requesting all needed locks at once at the beginning of a query
+ and always locking the tables in the same order.
+ </para>
+
+ <para>
+ MySQL grants table write locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no locks on the table, put a write lock on it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the write lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ MySQL grants table read locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no write locks on the table, put a read lock on
+ it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the read lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ Table updates are given higher priority than table retrievals.
+ Therefore, when a lock is released, the lock is made available
+ to the requests in the write lock queue and then to the requests
+ in the read lock queue. This ensures that updates to a table are
+ not <quote>starved</quote> even if there is heavy
+ <literal role="stmt">SELECT</literal> activity for the table.
+ However, if you have many updates for a table,
+ <literal role="stmt">SELECT</literal> statements wait until
+ there are no more updates.
+ </para>
+
+ <para>
+ For information on altering the priority of reads and writes,
+ see <xref linkend="table-locking"/>.
+ </para>
+
+ <para>
+ You can analyze the table lock contention on your system by
+ checking the
+ <literal role="statvar">Table_locks_immediate</literal> and
+ <literal role="statvar">Table_locks_waited</literal> status
+ variables, which indicate the number of times that requests for
+ table locks could be granted immediately and the number that had
+ to wait, respectively:
+ </para>
+
+<programlisting>
+mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
++-----------------------+---------+
+| Variable_name | Value |
++-----------------------+---------+
+| Table_locks_immediate | 1151552 |
+| Table_locks_waited | 15324 |
++-----------------------+---------+
+</programlisting>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no free
+ blocks in the middle of the data file, rows are always inserted
+ at the end of the data file. In this case, you can freely mix
+ concurrent <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> statements for a
+ <literal>MyISAM</literal> table without locks. That is, you can
+ insert rows into a <literal>MyISAM</literal> table at the same
+ time other clients are reading from it. Holes can result from
+ rows having been deleted from or updated in the middle of the
+ table. If there are holes, concurrent inserts are disabled but
+ are enabled again automatically when all holes have been filled
+ with new data. This behavior is altered by the
+ <literal role="sysvar">concurrent_insert</literal> system
+ variable. See <xref linkend="concurrent-inserts"/>.
+ </para>
+
+ <para>
+ If you acquire a table lock explicitly with
+ <literal role="stmt">LOCK TABLES</literal>, you can request a
+ <literal>READ LOCAL</literal> lock rather than a
+ <literal>READ</literal> lock to enable other sessions to perform
+ concurrent inserts while you have the table locked.
+ </para>
+
+ <para>
+ To perform many <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> operations on a table
+ <literal>real_table</literal> when concurrent inserts are not
+ possible, you can insert rows into a temporary table
+ <literal>temp_table</literal> and update the real table with the
+ rows from the temporary table periodically. This can be done
+ with the following code:
+ </para>
+
+<programlisting>
+mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
+mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
+mysql> <userinput>DELETE FROM temp_table;</userinput>
+mysql> <userinput>UNLOCK TABLES;</userinput>
+</programlisting>
+
+ <para>
+ <literal>InnoDB</literal> uses row locks and
+ <literal>BDB</literal> uses page locks. Deadlocks are possible
+ for these storage engines because they automatically acquire
+ locks during the processing of SQL statements, not at the start
+ of the transaction.
+ </para>
+
+ <para>
+ Advantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Fewer lock conflicts when different sessions access
+ different rows
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fewer changes for rollbacks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Possible to lock a single row for a long time
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Disadvantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Requires more memory than page-level or table-level locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than page-level or table-level locks when used on a
+ large part of the table because you must acquire many more
+ locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than other locks if you often do <literal>GROUP
+ BY</literal> operations on a large part of the data or if
+ you must scan the entire table frequently
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Generally, table locks are superior to page-level or row-level
+ locks in the following cases:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Most statements for the table are reads
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Statements for the table are a mix of reads and writes,
+ where writes are updates or deletes for a single row that
+ can be fetched with one key read:
+ </para>
+
+<programlisting>
+UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal role="stmt">SELECT</literal> combined with
+ concurrent <literal role="stmt">INSERT</literal> statements,
+ and very few <literal role="stmt">UPDATE</literal> or
+ <literal role="stmt">DELETE</literal> statements
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Many scans or <literal>GROUP BY</literal> operations on the
+ entire table without any writers
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With higher-level locks, you can more easily tune applications
+ by supporting locks of different types, because the lock
+ overhead is less than for row-level locks.
+ </para>
+
+ <para>
+ Options other than row-level or page-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Versioning (such as that used in MySQL for concurrent
+ inserts) where it is possible to have one writer at the same
+ time as many readers. This means that the database or table
+ supports different views for the data depending on when
+ access begins. Other common terms for this are <quote>time
+ travel,</quote> <quote>copy on write,</quote> or <quote>copy
+ on demand.</quote>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Copy on demand is in many cases superior to page-level or
+ row-level locking. However, in the worst case, it can use
+ much more memory than using normal locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Instead of using row-level locks, you can employ
+ application-level locks, such as those provided by
+ <literal role="func">GET_LOCK()</literal> and
+ <literal role="func">RELEASE_LOCK()</literal> in MySQL.
+ These are advisory locks, so they work only with
+ applications that cooperate with each other. See
+ <xref linkend="miscellaneous-functions"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="table-locking">
+
+ <title>Table Locking Issues</title>
+
+ <indexterm>
+ <primary>problems</primary>
+ <secondary>table locking</secondary>
+ </indexterm>
+
+ <para>
+ To achieve a very high lock speed, MySQL uses table locking
+ (instead of page, row, or column locking) for all storage
+ engines except <literal>InnoDB</literal>,
+ <literal>BDB</literal>, and
+ <literal role="se">NDBCLUSTER</literal>.
+ </para>
+
+ <para>
+ For <literal>InnoDB</literal> and <literal>BDB</literal> tables,
+ MySQL uses table locking only if you explicitly lock the table
+ with <literal role="stmt">LOCK TABLES</literal>. For these
+ storage engines, avoid using <literal role="stmt">LOCK
+ TABLES</literal> at all, because <literal>InnoDB</literal> uses
+ automatic row-level locking and <literal>BDB</literal> uses
+ page-level locking to ensure transaction isolation.
+ </para>
+
+ <para>
+ For large tables, table locking is often better than row
+ locking, but there are some disadvantages:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Table locking enables many sessions to read from a table at
+ the same time, but if a session wants to write to a table,
+ it must first get exclusive access. During the update, all
+ other sessions that want to access this particular table
+ must wait until the update is done.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Table locking causes problems in cases such as when a
+ session is waiting because the disk is full and free space
+ needs to become available before the session can proceed. In
+ this case, all sessions that want to access the problem
+ table are also put in a waiting state until more disk space
+ is made available.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Table locking is also disadvantageous under the following
+ scenario:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ A session issues a <literal role="stmt">SELECT</literal>
+ that takes a long time to run.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session then issues an
+ <literal role="stmt">UPDATE</literal> on the same table.
+ This session waits until the
+ <literal role="stmt">SELECT</literal> is finished.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session issues another
+ <literal role="stmt">SELECT</literal> statement on the same
+ table. Because <literal role="stmt">UPDATE</literal> has
+ higher priority than <literal role="stmt">SELECT</literal>,
+ this <literal role="stmt">SELECT</literal> waits for the
+ <literal role="stmt">UPDATE</literal> to finish,
+ <emphasis>after</emphasis> waiting for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following items describe some ways to avoid or reduce
+ contention caused by table locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Try to get the <literal role="stmt">SELECT</literal>
+ statements to run faster so that they lock tables for a
+ shorter time. You might have to create some summary tables
+ to do this.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with
+ <option role="mysqld">--low-priority-updates</option>. For
+ storage engines that use only table-level locking (such as
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
+ <literal>MERGE</literal>), this gives all statements that
+ update (modify) a table lower priority than
+ <literal role="stmt">SELECT</literal> statements. In this
+ case, the second <literal role="stmt">SELECT</literal>
+ statement in the preceding scenario would execute before the
+ <literal role="stmt">UPDATE</literal> statement, and would
+ not need to wait for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To specify that all updates issued in a specific connection
+ should be done with low priority, set the
+ <literal role="sysvar">low_priority_updates</literal> server
+ system variable equal to 1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">INSERT</literal>,
+ <literal role="stmt">UPDATE</literal>, or
+ <literal role="stmt">DELETE</literal> statement lower
+ priority, use the <literal>LOW_PRIORITY</literal> attribute.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">SELECT</literal>
+ statement higher priority, use the
+ <literal>HIGH_PRIORITY</literal> attribute. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with a low value for the
+ <literal role="sysvar">max_write_lock_count</literal> system
+ variable to force MySQL to temporarily elevate the priority
+ of all <literal role="stmt">SELECT</literal> statements that
+ are waiting for a table after a specific number of inserts
+ to the table occur. This permits <literal>READ</literal>
+ locks after a certain number of <literal>WRITE</literal>
+ locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with
+ <literal role="stmt">INSERT</literal> combined with
+ <literal role="stmt">SELECT</literal>, consider switching to
+ <literal>MyISAM</literal> tables, which support concurrent
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">INSERT</literal> statements. (See
+ <xref linkend="concurrent-inserts"/>.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you mix inserts and deletes on the same table,
+ <literal role="stmt">INSERT DELAYED</literal> may be of
+ great help. See <xref linkend="insert-delayed"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with mixed
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">DELETE</literal> statements, the
+ <literal>LIMIT</literal> option to
+ <literal role="stmt">DELETE</literal> may help. See
+ <xref linkend="delete"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Using <literal>SQL_BUFFER_RESULT</literal> with
+ <literal role="stmt">SELECT</literal> statements can help to
+ make the duration of table locks shorter. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You could change the locking code in
+ <filename>mysys/thr_lock.c</filename> to use a single queue.
+ In this case, write locks and read locks would have the same
+ priority, which might help some applications.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Here are some tips concerning table locks in MySQL:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Concurrent users are not a problem if you do not mix updates
+ with selects that need to examine many rows in the same
+ table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can use <literal role="stmt">LOCK TABLES</literal> to
+ increase speed, because many updates within a single lock is
+ much faster than updating without locks. Splitting table
+ contents into separate tables may also help.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you encounter speed problems with table locks in MySQL,
+ you may be able to improve performance by converting some of
+ your tables to <literal>InnoDB</literal> or
+ <literal>BDB</literal> tables. See <xref linkend="innodb"/>,
+ and <xref linkend="bdb-storage-engine"/>.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ Lock contention can seriously degrade performance. The
+ MySQL Enterprise Monitor provides expert advice on
+ avoiding this problem. To subscribe, see
+ &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="concurrent-inserts">
+
+ <title>Concurrent Inserts</title>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no holes
+ in the data file (deleted rows in the middle), an
+ <literal role="stmt">INSERT</literal> statement can be executed
+ to add rows to the end of the table at the same time that
+ <literal role="stmt">SELECT</literal> statements are reading
+ rows from the table. If there are multiple
+ <literal role="stmt">INSERT</literal> statements, they are
+ queued and performed in sequence, concurrently with the
+ <literal role="stmt">SELECT</literal> statements. The results of
+ a concurrent <literal role="stmt">INSERT</literal> may not be
+ visible immediately.
+ </para>
+
+ <para>
+ The <literal role="sysvar">concurrent_insert</literal> system
+ variable can be set to modify the concurrent-insert processing.
+ By default, the variable is set to 1 and concurrent inserts are
+ handled as just described. If
+ <literal role="sysvar">concurrent_insert</literal> is set to 0,
+ concurrent inserts are disabled. If the variable is set to 2,
+ concurrent inserts at the end of the table are allowed even for
+ tables that have deleted rows. See also the description of the
+ <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
+ system variable.
+ </para>
+
+ <para>
+ Under circumstances where concurrent inserts can be used, there
+ is seldom any need to use the <literal>DELAYED</literal>
+ modifier for <literal role="stmt">INSERT</literal> statements.
+ See <xref linkend="insert-delayed"/>.
+ </para>
+
+ <para>
+ If you are using the binary log, concurrent inserts are
+ converted to normal inserts for <literal>CREATE ...
+ SELECT</literal> or
+ <literal role="stmt" condition="insert-select">INSERT ...
+ SELECT</literal> statements. This is done to ensure that you can
+ re-create an exact copy of your tables by applying the log
+ during a backup operation. See <xref linkend="binary-log"/>. In
+ addition, for those statements a read lock is placed on the
+ selected-from table such that inserts into that table are
+ blocked. The effect is that concurrent inserts for that table
+ must wait as well.
+ </para>
+
+ <para>
+ With <literal role="stmt" condition="load-data">LOAD DATA
+ INFILE</literal>, if you specify <literal>CONCURRENT</literal>
+ with a <literal>MyISAM</literal> table that satisfies the
+ condition for concurrent inserts (that is, it contains no free
+ blocks in the middle), other sessions can retrieve data from the
+ table while <literal role="stmt">LOAD DATA</literal> is
+ executing. Use of the <literal>CONCURRENT</literal> option
+ affects the performance of <literal role="stmt">LOAD
+ DATA</literal> a bit, even if no other session is using the
+ table at the same time.
+ </para>
+
+ <para>
+ If you specify <literal>HIGH_PRIORITY</literal>, it overrides
+ the effect of the
+ <option role="mysqld">--low-priority-updates</option> option if
+ the server was started with that option. It also causes
+ concurrent inserts not to be used.
+ </para>
+
+ <para>
+ For <literal role="stmt" condition="lock-tables">LOCK
+ TABLE</literal>, the difference between <literal>READ
+ LOCAL</literal> and <literal>READ</literal> is that
+ <literal>READ LOCAL</literal> permits nonconflicting
+ <literal role="stmt">INSERT</literal> statements (concurrent
+ inserts) to execute while the lock is held. However, this cannot
+ be used if you are going to manipulate the database using
+ processes external to the server while you hold the lock.
+ </para>
+
+ </section>
+
+ <section id="external-locking">
+
+ <title>External Locking</title>
+
+ <indexterm>
+ <primary>external locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>external</secondary>
+ </indexterm>
+
+ <para>
+ External locking is the use of file system locking to manage
+ contention for database tables by multiple processes. External
+ locking is used in situations where a single process such as the
+ MySQL server cannot be assumed to be the only process that
+ requires access to tables. Here are some examples:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ If you run multiple servers that use the same database
+ directory (not recommended), each server must have external
+ locking enabled.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you use <command>myisamchk</command> to perform table
+ maintenance operations on <literal>MyISAM</literal> tables,
+ you must either ensure that the server is not running, or
+ that the server has external locking enabled so that it
+ locks table files as necessary to coordinate with
+ <command>myisamchk</command> for access to the tables. The
+ same is true for use of <command>myisampack</command> to
+ pack <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ If the server is run with external locking enabled, you can
+ use <command>myisamchk</command> at any time for read
+ operations such a checking tables. In this case, if the
+ server tries to update a table that
+ <command>myisamchk</command> is using, the server will wait
+ for <command>myisamchk</command> to finish before it
+ continues.
+ </para>
+
+ <para>
+ If you use <command>myisamchk</command> for write operations
+ such as repairing or optimizing tables, or if you use
+ <command>myisampack</command> to pack tables, you
+ <emphasis>must</emphasis> always ensure that the
+ <command>mysqld</command> server is not using the table. If
+ you don't stop <command>mysqld</command>, you should at
+ least do a <command>mysqladmin flush-tables</command> before
+ you run <command>myisamchk</command>. Your tables
+ <emphasis>may become corrupted</emphasis> if the server and
+ <command>myisamchk</command> access the tables
+ simultaneously.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With external locking in effect, each process that requires
+ access to a table acquires a file system lock for the table
+ files before proceeding to access the table. If all necessary
+ locks cannot be acquired, the process is blocked from accessing
+ the table until the locks can be obtained (after the process
+ that currently holds the locks releases them).
+ </para>
+
+ <para>
+ External locking affects server performance because the server
+ must sometimes wait for other processes before it can access
+ tables.
+ </para>
+
+ <para>
+ External locking is unnecessary if you run a single server to
+ access a given data directory (which is the usual case) and if
+ no other programs such as <command>myisamchk</command> need to
+ modify tables while the server is running. If you only
+ <emphasis>read</emphasis> tables with other programs, external
+ locking is not required, although <command>myisamchk</command>
+ might report warnings if the server changes tables while
+ <command>myisamchk</command> is reading them.
+ </para>
+
+ <para>
+ With external locking disabled, to use
+ <command>myisamchk</command>, you must either stop the server
+ while <command>myisamchk</command> executes or else lock and
+ flush the tables before running <command>myisamchk</command>.
+ (See <xref linkend="system-optimization"/>.) To avoid this
+ requirement, use the <literal role="stmt">CHECK TABLE</literal>
+ and <literal role="stmt">REPAIR TABLE</literal> statements to
+ check and repair <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ For <command>mysqld</command>, external locking is controlled by
+ the value of the
+ <literal role="sysvar">skip_external_locking</literal> system
+ variable. When this variable is enabled, external locking is
+ disabled, and vice versa. From MySQL 4.0 on, external locking is
+ disabled by default. Before MySQL 4.0, external locking is
+ enabled by default on Linux or when MySQL is configured to use
+ MIT-pthreads.
+ </para>
+
+ <para>
+ Use of external locking can be controlled at server startup by
+ using the <option role="mysqld">--external-locking</option> or
+ <option role="mysqld">--skip-external-locking</option> option.
+ </para>
+
+ <para>
+ If you do use external locking option to enable updates to
+ <literal>MyISAM</literal> tables from many MySQL processes, you
+ must ensure that the following conditions are satisfied:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ You should not use the query cache for queries that use
+ tables that are updated by another process.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You should not start the server with the
+ <option role="mysqld">--delay-key-write=ALL</option> option
+ or use the <literal>DELAY_KEY_WRITE=1</literal> table option
+ for any shared tables. Otherwise, index corruption can
+ occur.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The easiest way to satisfy these conditions is to always use
+ <option role="mysqld">--external-locking</option> together with
+ <option role="mysqld">--delay-key-write=OFF</option> and
+ <option role="sysvar">--query-cache-size=0</option>. (This is
+ not done by default because in many setups it is useful to have
+ a mixture of the preceding options.)
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="optimizing-database-structure">
+
+ <title>Optimizing Database Structure</title>
+
+ <section id="data-size">
+
+ <title>Make Your Data as Small as Possible</title>
+
+ <indexterm>
+ <primary>data</primary>
+ <secondary>size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>reducing</primary>
+ <secondary>data size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>storage space</primary>
+ <secondary>minimizing</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>tables</primary>
+ <secondary>improving performance</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>performance</primary>
+ <secondary>improving</secondary>
+ </indexterm>
+
+ <para>
+ One of the most basic optimizations is to design your tables to
+ take as little space on the disk as possible. This can result in
+ huge improvements because disk reads are faster, and smaller
+ tables normally require less main memory while their contents
+ are being actively processed during query execution. Indexing
+ also is a lesser resource burden if done on smaller columns.
+ </para>
+
+ <para>
+ MySQL supports many different storage engines (table types) and
+ row formats. For each table, you can decide which storage and
+ indexing method to use. Choosing the proper table format for
+ your application may give you a big performance gain. See
+ <xref linkend="storage-engines"/>.
+ </para>
+
+ <para>
+ You can get better performance for a table and minimize storage
+ space by using the techniques listed here:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Use the most efficient (smallest) data types possible. MySQL
+ has many specialized types that save disk space and memory.
+ For example, use the smaller integer types if possible to
+ get smaller tables. <literal role="type">MEDIUMINT</literal>
+ is often a better choice than
+ <literal role="type">INT</literal> because a
+ <literal role="type">MEDIUMINT</literal> column uses 25%
+ less space.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Declare columns to be <literal>NOT NULL</literal> if
+ possible. It makes everything faster and you save one bit
+ per column. If you really need <literal>NULL</literal> in
+ your application, you should definitely use it. Just avoid
+ having it on all columns by default.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For <literal>MyISAM</literal> tables, if you do not have any
+ variable-length columns
+ (<literal role="type">VARCHAR</literal>,
+ <literal role="type">TEXT</literal>, or
+ <literal role="type">BLOB</literal> columns), a fixed-size
+ row format is used. This is faster but unfortunately may
+ waste some space. See
+ <xref linkend="myisam-table-formats"/>. You can hint that
+ you want to have fixed length rows even if you have
+ <literal role="type">VARCHAR</literal> columns with the
+ <literal role="stmt">CREATE TABLE</literal> option
+ <literal>ROW_FORMAT=FIXED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Starting with MySQL 5.0.3, <literal>InnoDB</literal> tables
+ use a more compact storage format. In earlier versions of
+ MySQL, <literal>InnoDB</literal> rows contain some redundant
+ information, such as the number of columns and the length of
+ each column, even for fixed-size columns. By default, tables
+ are created in the compact format
+ (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
+ downgrade to older versions of MySQL, you can request the
+ old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
+ </para>
+
+ <para>
+ The presence of the compact row format decreases row storage
+ space by about 20% at the cost of increasing CPU use for
+ some operations. If your workload is a typical one that is
+ limited by cache hit rates and disk speed it is likely to be
+ faster. If it is a rare case that is limited by CPU speed,
+ it might be slower.
+ </para>
+
+ <para>
+ The compact <literal>InnoDB</literal> format also changes
+ how <literal role="type">CHAR</literal> columns containing
+ UTF-8 data are stored. With
+ <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
+ <literal>CHAR(<replaceable>N</replaceable>)</literal>
+ occupies 3 × <replaceable>N</replaceable> bytes, given
+ that the maximum length of a UTF-8 encoded character is
+ three bytes. Many languages can be written primarily using
+ single-byte UTF-8 characters, so a fixed storage length
+ often wastes space. With
+ <literal>ROW_FORMAT=COMPACT</literal> format,
+ <literal>InnoDB</literal> allocates a variable amount of
+ storage in the range from <replaceable>N</replaceable> to 3
+ × <replaceable>N</replaceable> bytes for these columns
+ by stripping trailing spaces if necessary. The minimum
+ storage length is kept as <replaceable>N</replaceable> bytes
+ to facilitate in-place updates in typical cases.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The primary index of a table should be as short as possible.
+ This makes identification of each row easy and efficient.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create only the indexes that you really need. Indexes are
+ good for retrieval but bad when you need to store data
+ quickly. If you access a table mostly by searching on a
+ combination of columns, create an index on them. The first
+ part of the index should be the column most used. If you
+ <emphasis>always</emphasis> use many columns when selecting
+ from the table, the first column in the index should be the
+ one with the most duplicates to obtain better compression of
+ the index.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If it is very likely that a string column has a unique
+ prefix on the first number of characters, it is better to
+ index only this prefix, using MySQL's support for creating
+ an index on the leftmost part of the column (see
+ <xref linkend="create-index"/>). Shorter indexes are faster,
+ not only because they require less disk space, but because
+ they also give you more hits in the index cache, and thus
+ fewer disk seeks. See <xref linkend="server-parameters"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ In some circumstances, it can be beneficial to split into
+ two a table that is scanned very often. This is especially
+ true if it is a dynamic-format table and it is possible to
+ use a smaller static format table that can be used to find
+ the relevant rows when scanning the table.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
<section id="table-cache">
<title>How MySQL Opens and Closes Tables</title>
Modified: trunk/refman-5.0/renamed-nodes.txt
===================================================================
--- trunk/refman-5.0/renamed-nodes.txt 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.0/renamed-nodes.txt 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 0; 619 bytes
@@ -42,6 +42,7 @@
eiffel apis-eiffel 2009-09-01
german-character-set charset-we-sets 2010-08-08
group-by-hidden-fields group-by-hidden-columns 2010-01-01
+indexes column-indexes 2011-07-14
innodb-and-autocommit innodb-transaction-model 2009-11-24
innodb-consistent-read-example innodb-consistent-read 2010-03-10
innodb-general-monitor innodb-monitors 2010-11-05
Modified: trunk/refman-5.0/sql-syntax-data-definition.xml
===================================================================
--- trunk/refman-5.0/sql-syntax-data-definition.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.0/sql-syntax-data-definition.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 663 bytes
@@ -3168,7 +3168,7 @@
<literal role="type">VARBINARY</literal>, and
<literal role="type">BLOB</literal> columns. Indexing only a
prefix of column values like this can make the index file much
- smaller. See <xref linkend="indexes"/>.
+ smaller. See <xref linkend="column-indexes"/>.
</para>
<indexterm>
Modified: trunk/refman-5.1/data-types.xml
===================================================================
--- trunk/refman-5.1/data-types.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.1/data-types.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 594 bytes
@@ -4648,7 +4648,7 @@
specify an index prefix length. For
<literal role="type">CHAR</literal> and
<literal role="type">VARCHAR</literal>, a prefix length is
- optional. See <xref linkend="indexes"/>.
+ optional. See <xref linkend="column-indexes"/>.
</para>
</listitem>
Modified: trunk/refman-5.1/optimization.xml
===================================================================
--- trunk/refman-5.1/optimization.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.1/optimization.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 3, Lines Added: 1132, Lines Deleted: 1126; 83198 bytes
@@ -8652,1134 +8652,12 @@
</section>
- <section id="locking-issues">
+ <section id="optimization-indexes">
- <title>Locking Issues</title>
+ <title>Optimization and Indexes</title>
- <para>
- MySQL manages contention for table contents using locking:
- </para>
+ <section id="column-indexes">
- <itemizedlist>
-
- <listitem>
- <para>
- Internal locking is performed within the MySQL server itself
- to manage contention for table contents by multiple threads.
- This type of locking is internal because it is performed
- entirely by the server and involves no other programs. See
- <xref linkend="internal-locking"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- External locking occurs when the server and other programs
- lock table files to coordinate among themselves which program
- can access the tables at which time. See
- <xref linkend="external-locking"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <section id="internal-locking">
-
- <title>Internal Locking Methods</title>
-
- <indexterm>
- <primary>internal locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>internal</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking methods</primary>
- </indexterm>
-
- <indexterm>
- <primary>methods</primary>
- <secondary>locking</secondary>
- </indexterm>
-
- <indexterm>
- <primary>row-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>table-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>row-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>table-level</secondary>
- </indexterm>
-
- <para>
- This section discusses internal locking; that is, locking
- performed within the MySQL server itself to manage contention
- for table contents by multiple sessions. This type of locking is
- internal because it is performed entirely by the server and
- involves no other programs. External locking occurs when the
- server and other programs lock table files to coordinate among
- themselves which program can access the tables at which time.
- See <xref linkend="external-locking"/>.
- </para>
-
- <para>
- MySQL uses table-level locking for <literal>MyISAM</literal>,
- <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
- and row-level locking for <literal>InnoDB</literal> tables.
- </para>
-
- <para>
- In many cases, you can make an educated guess about which
- locking type is best for an application, but generally it is
- difficult to say that a given lock type is better than another.
- Everything depends on the application and different parts of an
- application may require different lock types.
- </para>
-
- <para>
- To decide whether you want to use a storage engine with
- row-level locking, you should look at what your application does
- and what mix of select and update statements it uses. For
- example, most Web applications perform many selects, relatively
- few deletes, updates based mainly on key values, and inserts
- into a few specific tables. The base MySQL
- <literal>MyISAM</literal> setup is very well tuned for this.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- The MySQL Enterprise Monitor provides expert advice on when to
- use table-level locking and when to use row-level locking. To
- subscribe, see &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
-
- <para>
- Table locking in MySQL is deadlock-free for storage engines that
- use table-level locking. Deadlock avoidance is managed by always
- requesting all needed locks at once at the beginning of a query
- and always locking the tables in the same order.
- </para>
-
- <para>
- MySQL grants table write locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no locks on the table, put a write lock on it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the write lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- MySQL grants table read locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no write locks on the table, put a read lock on
- it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the read lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- Table updates are given higher priority than table retrievals.
- Therefore, when a lock is released, the lock is made available
- to the requests in the write lock queue and then to the requests
- in the read lock queue. This ensures that updates to a table are
- not <quote>starved</quote> even if there is heavy
- <literal role="stmt">SELECT</literal> activity for the table.
- However, if you have many updates for a table,
- <literal role="stmt">SELECT</literal> statements wait until
- there are no more updates.
- </para>
-
- <para>
- For information on altering the priority of reads and writes,
- see <xref linkend="table-locking"/>.
- </para>
-
- <para>
- You can analyze the table lock contention on your system by
- checking the
- <literal role="statvar">Table_locks_immediate</literal> and
- <literal role="statvar">Table_locks_waited</literal> status
- variables, which indicate the number of times that requests for
- table locks could be granted immediately and the number that had
- to wait, respectively:
- </para>
-
-<programlisting>
-mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
-+-----------------------+---------+
-| Variable_name | Value |
-+-----------------------+---------+
-| Table_locks_immediate | 1151552 |
-| Table_locks_waited | 15324 |
-+-----------------------+---------+
-</programlisting>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no free
- blocks in the middle of the data file, rows are always inserted
- at the end of the data file. In this case, you can freely mix
- concurrent <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> statements for a
- <literal>MyISAM</literal> table without locks. That is, you can
- insert rows into a <literal>MyISAM</literal> table at the same
- time other clients are reading from it. Holes can result from
- rows having been deleted from or updated in the middle of the
- table. If there are holes, concurrent inserts are disabled but
- are enabled again automatically when all holes have been filled
- with new data.. This behavior is altered by the
- <literal role="sysvar">concurrent_insert</literal> system
- variable. See <xref linkend="concurrent-inserts"/>.
- </para>
-
- <para>
- If you acquire a table lock explicitly with
- <literal role="stmt">LOCK TABLES</literal>, you can request a
- <literal>READ LOCAL</literal> lock rather than a
- <literal>READ</literal> lock to enable other sessions to perform
- concurrent inserts while you have the table locked.
- </para>
-
- <para>
- To perform many <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> operations on a table
- <literal>real_table</literal> when concurrent inserts are not
- possible, you can insert rows into a temporary table
- <literal>temp_table</literal> and update the real table with the
- rows from the temporary table periodically. This can be done
- with the following code:
- </para>
-
-<programlisting>
-mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
-mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
-mysql> <userinput>DELETE FROM temp_table;</userinput>
-mysql> <userinput>UNLOCK TABLES;</userinput>
-</programlisting>
-
- <para>
- <literal>InnoDB</literal> uses row locks. Deadlocks are possible
- for <literal>InnoDB</literal> because it automatically acquires
- locks during the processing of SQL statements, not at the start
- of the transaction.
- </para>
-
- <para>
- Advantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Fewer lock conflicts when different sessions access
- different rows
- </para>
- </listitem>
-
- <listitem>
- <para>
- Fewer changes for rollbacks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Possible to lock a single row for a long time
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Disadvantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Requires more memory than table-level locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than table-level locks when used on a large part of
- the table because you must acquire many more locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than other locks if you often do <literal>GROUP
- BY</literal> operations on a large part of the data or if
- you must scan the entire table frequently
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Generally, table locks are superior to row-level locks in the
- following cases:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Most statements for the table are reads
- </para>
- </listitem>
-
- <listitem>
- <para>
- Statements for the table are a mix of reads and writes,
- where writes are updates or deletes for a single row that
- can be fetched with one key read:
- </para>
-
-<programlisting>
-UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-</programlisting>
- </listitem>
-
- <listitem>
- <para>
- <literal role="stmt">SELECT</literal> combined with
- concurrent <literal role="stmt">INSERT</literal> statements,
- and very few <literal role="stmt">UPDATE</literal> or
- <literal role="stmt">DELETE</literal> statements
- </para>
- </listitem>
-
- <listitem>
- <para>
- Many scans or <literal>GROUP BY</literal> operations on the
- entire table without any writers
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With higher-level locks, you can more easily tune applications
- by supporting locks of different types, because the lock
- overhead is less than for row-level locks.
- </para>
-
- <para>
- Options other than row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Versioning (such as that used in MySQL for concurrent
- inserts) where it is possible to have one writer at the same
- time as many readers. This means that the database or table
- supports different views for the data depending on when
- access begins. Other common terms for this are <quote>time
- travel,</quote> <quote>copy on write,</quote> or <quote>copy
- on demand.</quote>
- </para>
- </listitem>
-
- <listitem>
- <para>
- Copy on demand is in many cases superior to row-level
- locking. However, in the worst case, it can use much more
- memory than using normal locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Instead of using row-level locks, you can employ
- application-level locks, such as those provided by
- <literal role="func">GET_LOCK()</literal> and
- <literal role="func">RELEASE_LOCK()</literal> in MySQL.
- These are advisory locks, so they work only with
- applications that cooperate with each other. See
- <xref linkend="miscellaneous-functions"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="table-locking">
-
- <title>Table Locking Issues</title>
-
- <indexterm>
- <primary>problems</primary>
- <secondary>table locking</secondary>
- </indexterm>
-
- <para>
- To achieve a very high lock speed, MySQL uses table locking
- (instead of page, row, or column locking) for all storage
- engines except <literal>InnoDB</literal> and
- <literal role="se">NDBCLUSTER</literal>.
- </para>
-
- <para>
- For <literal>InnoDB</literal> tables, MySQL uses table locking
- only if you explicitly lock the table with
- <literal role="stmt">LOCK TABLES</literal>. For this storage
- engine, avoid using <literal role="stmt">LOCK TABLES</literal>
- at all, because <literal>InnoDB</literal> uses automatic
- row-level locking to ensure transaction isolation.
- </para>
-
- <para>
- For large tables, table locking is often better than row
- locking, but there are some disadvantages:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Table locking enables many sessions to read from a table at
- the same time, but if a session wants to write to a table,
- it must first get exclusive access. During the update, all
- other sessions that want to access this particular table
- must wait until the update is done.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Table locking causes problems in cases such as when a
- session is waiting because the disk is full and free space
- needs to become available before the session can proceed. In
- this case, all sessions that want to access the problem
- table are also put in a waiting state until more disk space
- is made available.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Table locking is also disadvantageous under the following
- scenario:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A session issues a <literal role="stmt">SELECT</literal>
- that takes a long time to run.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session then issues an
- <literal role="stmt">UPDATE</literal> on the same table.
- This session waits until the
- <literal role="stmt">SELECT</literal> is finished.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session issues another
- <literal role="stmt">SELECT</literal> statement on the same
- table. Because <literal role="stmt">UPDATE</literal> has
- higher priority than <literal role="stmt">SELECT</literal>,
- this <literal role="stmt">SELECT</literal> waits for the
- <literal role="stmt">UPDATE</literal> to finish,
- <emphasis>after</emphasis> waiting for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following items describe some ways to avoid or reduce
- contention caused by table locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Try to get the <literal role="stmt">SELECT</literal>
- statements to run faster so that they lock tables for a
- shorter time. You might have to create some summary tables
- to do this.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with
- <option role="mysqld">--low-priority-updates</option>. For
- storage engines that use only table-level locking (such as
- <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
- <literal>MERGE</literal>), this gives all statements that
- update (modify) a table lower priority than
- <literal role="stmt">SELECT</literal> statements. In this
- case, the second <literal role="stmt">SELECT</literal>
- statement in the preceding scenario would execute before the
- <literal role="stmt">UPDATE</literal> statement, and would
- not need to wait for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To specify that all updates issued in a specific connection
- should be done with low priority, set the
- <literal role="sysvar">low_priority_updates</literal> server
- system variable equal to 1.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">INSERT</literal>,
- <literal role="stmt">UPDATE</literal>, or
- <literal role="stmt">DELETE</literal> statement lower
- priority, use the <literal>LOW_PRIORITY</literal> attribute.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">SELECT</literal>
- statement higher priority, use the
- <literal>HIGH_PRIORITY</literal> attribute. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with a low value for the
- <literal role="sysvar">max_write_lock_count</literal> system
- variable to force MySQL to temporarily elevate the priority
- of all <literal role="stmt">SELECT</literal> statements that
- are waiting for a table after a specific number of inserts
- to the table occur. This permits <literal>READ</literal>
- locks after a certain number of <literal>WRITE</literal>
- locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with
- <literal role="stmt">INSERT</literal> combined with
- <literal role="stmt">SELECT</literal>, consider switching to
- <literal>MyISAM</literal> tables, which support concurrent
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">INSERT</literal> statements. (See
- <xref linkend="concurrent-inserts"/>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you mix inserts and deletes on the same table,
- <literal role="stmt">INSERT DELAYED</literal> may be of
- great help. See <xref linkend="insert-delayed"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with mixed
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">DELETE</literal> statements, the
- <literal>LIMIT</literal> option to
- <literal role="stmt">DELETE</literal> may help. See
- <xref linkend="delete"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Using <literal>SQL_BUFFER_RESULT</literal> with
- <literal role="stmt">SELECT</literal> statements can help to
- make the duration of table locks shorter. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You could change the locking code in
- <filename>mysys/thr_lock.c</filename> to use a single queue.
- In this case, write locks and read locks would have the same
- priority, which might help some applications.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Here are some tips concerning table locks in MySQL:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Concurrent users are not a problem if you do not mix updates
- with selects that need to examine many rows in the same
- table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can use <literal role="stmt">LOCK TABLES</literal> to
- increase speed, because many updates within a single lock is
- much faster than updating without locks. Splitting table
- contents into separate tables may also help.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you encounter speed problems with table locks in MySQL,
- you may be able to improve performance by converting some of
- your tables to <literal>InnoDB</literal>. See
- <xref linkend="innodb"/>.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- Lock contention can seriously degrade performance. The
- MySQL Enterprise Monitor provides expert advice on
- avoiding this problem. To subscribe, see
- &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="concurrent-inserts">
-
- <title>Concurrent Inserts</title>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no holes
- in the data file (deleted rows in the middle), an
- <literal role="stmt">INSERT</literal> statement can be executed
- to add rows to the end of the table at the same time that
- <literal role="stmt">SELECT</literal> statements are reading
- rows from the table. If there are multiple
- <literal role="stmt">INSERT</literal> statements, they are
- queued and performed in sequence, concurrently with the
- <literal role="stmt">SELECT</literal> statements. The results of
- a concurrent <literal role="stmt">INSERT</literal> may not be
- visible immediately.
- </para>
-
- <para>
- The <literal role="sysvar">concurrent_insert</literal> system
- variable can be set to modify the concurrent-insert processing.
- By default, the variable is set to 1 and concurrent inserts are
- handled as just described. If
- <literal role="sysvar">concurrent_insert</literal> is set to 0,
- concurrent inserts are disabled. If the variable is set to 2,
- concurrent inserts at the end of the table are allowed even for
- tables that have deleted rows. See also the description of the
- <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
- system variable.
- </para>
-
- <para>
- Under circumstances where concurrent inserts can be used, there
- is seldom any need to use the <literal>DELAYED</literal>
- modifier for <literal role="stmt">INSERT</literal> statements.
- See <xref linkend="insert-delayed"/>.
- </para>
-
- <para>
- If you are using the binary log, concurrent inserts are
- converted to normal inserts for <literal>CREATE ...
- SELECT</literal> or
- <literal role="stmt" condition="insert-select">INSERT ...
- SELECT</literal> statements. This is done to ensure that you can
- re-create an exact copy of your tables by applying the log
- during a backup operation. See <xref linkend="binary-log"/>. In
- addition, for those statements a read lock is placed on the
- selected-from table such that inserts into that table are
- blocked. The effect is that concurrent inserts for that table
- must wait as well.
- </para>
-
- <para>
- With <literal role="stmt" condition="load-data">LOAD DATA
- INFILE</literal>, if you specify <literal>CONCURRENT</literal>
- with a <literal>MyISAM</literal> table that satisfies the
- condition for concurrent inserts (that is, it contains no free
- blocks in the middle), other sessions can retrieve data from the
- table while <literal role="stmt">LOAD DATA</literal> is
- executing. Use of the <literal>CONCURRENT</literal> option
- affects the performance of <literal role="stmt">LOAD
- DATA</literal> a bit, even if no other session is using the
- table at the same time.
- </para>
-
- <para>
- If you specify <literal>HIGH_PRIORITY</literal>, it overrides
- the effect of the
- <option role="mysqld">--low-priority-updates</option> option if
- the server was started with that option. It also causes
- concurrent inserts not to be used.
- </para>
-
- <para>
- For <literal role="stmt" condition="lock-tables">LOCK
- TABLE</literal>, the difference between <literal>READ
- LOCAL</literal> and <literal>READ</literal> is that
- <literal>READ LOCAL</literal> permits nonconflicting
- <literal role="stmt">INSERT</literal> statements (concurrent
- inserts) to execute while the lock is held. However, this cannot
- be used if you are going to manipulate the database using
- processes external to the server while you hold the lock.
- </para>
-
- </section>
-
- <section id="external-locking">
-
- <title>External Locking</title>
-
- <indexterm>
- <primary>external locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>external</secondary>
- </indexterm>
-
- <para>
- External locking is the use of file system locking to manage
- contention for database tables by multiple processes. External
- locking is used in situations where a single process such as the
- MySQL server cannot be assumed to be the only process that
- requires access to tables. Here are some examples:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- If you run multiple servers that use the same database
- directory (not recommended), each server must have external
- locking enabled.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you use <command>myisamchk</command> to perform table
- maintenance operations on <literal>MyISAM</literal> tables,
- you must either ensure that the server is not running, or
- that the server has external locking enabled so that it
- locks table files as necessary to coordinate with
- <command>myisamchk</command> for access to the tables. The
- same is true for use of <command>myisampack</command> to
- pack <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- If the server is run with external locking enabled, you can
- use <command>myisamchk</command> at any time for read
- operations such a checking tables. In this case, if the
- server tries to update a table that
- <command>myisamchk</command> is using, the server will wait
- for <command>myisamchk</command> to finish before it
- continues.
- </para>
-
- <para>
- If you use <command>myisamchk</command> for write operations
- such as repairing or optimizing tables, or if you use
- <command>myisampack</command> to pack tables, you
- <emphasis>must</emphasis> always ensure that the
- <command>mysqld</command> server is not using the table. If
- you don't stop <command>mysqld</command>, you should at
- least do a <command>mysqladmin flush-tables</command> before
- you run <command>myisamchk</command>. Your tables
- <emphasis>may become corrupted</emphasis> if the server and
- <command>myisamchk</command> access the tables
- simultaneously.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With external locking in effect, each process that requires
- access to a table acquires a file system lock for the table
- files before proceeding to access the table. If all necessary
- locks cannot be acquired, the process is blocked from accessing
- the table until the locks can be obtained (after the process
- that currently holds the locks releases them).
- </para>
-
- <para>
- External locking affects server performance because the server
- must sometimes wait for other processes before it can access
- tables.
- </para>
-
- <para>
- External locking is unnecessary if you run a single server to
- access a given data directory (which is the usual case) and if
- no other programs such as <command>myisamchk</command> need to
- modify tables while the server is running. If you only
- <emphasis>read</emphasis> tables with other programs, external
- locking is not required, although <command>myisamchk</command>
- might report warnings if the server changes tables while
- <command>myisamchk</command> is reading them.
- </para>
-
- <para>
- With external locking disabled, to use
- <command>myisamchk</command>, you must either stop the server
- while <command>myisamchk</command> executes or else lock and
- flush the tables before running <command>myisamchk</command>.
- (See <xref linkend="system-optimization"/>.) To avoid this
- requirement, use the <literal role="stmt">CHECK TABLE</literal>
- and <literal role="stmt">REPAIR TABLE</literal> statements to
- check and repair <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- For <command>mysqld</command>, external locking is controlled by
- the value of the
- <literal role="sysvar">skip_external_locking</literal> system
- variable. When this variable is enabled, external locking is
- disabled, and vice versa. From MySQL 4.0 on, external locking is
- disabled by default. Before MySQL 4.0, external locking is
- enabled by default on Linux or when MySQL is configured to use
- MIT-pthreads.
- </para>
-
- <para>
- Use of external locking can be controlled at server startup by
- using the <option role="mysqld">--external-locking</option> or
- <option role="mysqld">--skip-external-locking</option> option.
- </para>
-
- <para>
- If you do use external locking option to enable updates to
- <literal>MyISAM</literal> tables from many MySQL processes, you
- must ensure that the following conditions are satisfied:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- You should not use the query cache for queries that use
- tables that are updated by another process.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You should not start the server with the
- <option role="mysqld">--delay-key-write=ALL</option> option
- or use the <literal>DELAY_KEY_WRITE=1</literal> table option
- for any shared tables. Otherwise, index corruption can
- occur.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The easiest way to satisfy these conditions is to always use
- <option role="mysqld">--external-locking</option> together with
- <option role="mysqld">--delay-key-write=OFF</option> and
- <option role="sysvar">--query-cache-size=0</option>. (This is
- not done by default because in many setups it is useful to have
- a mixture of the preceding options.)
- </para>
-
- </section>
-
- </section>
-
- <section id="optimizing-database-structure">
-
- <title>Optimizing Database Structure</title>
-
- <section id="data-size">
-
- <title>Make Your Data as Small as Possible</title>
-
- <indexterm>
- <primary>data</primary>
- <secondary>size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>reducing</primary>
- <secondary>data size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>storage space</primary>
- <secondary>minimizing</secondary>
- </indexterm>
-
- <indexterm>
- <primary>tables</primary>
- <secondary>improving performance</secondary>
- </indexterm>
-
- <indexterm>
- <primary>performance</primary>
- <secondary>improving</secondary>
- </indexterm>
-
- <para>
- One of the most basic optimizations is to design your tables to
- take as little space on the disk as possible. This can result in
- huge improvements because disk reads are faster, and smaller
- tables normally require less main memory while their contents
- are being actively processed during query execution. Indexing
- also is a lesser resource burden if done on smaller columns.
- </para>
-
- <para>
- MySQL supports many different storage engines (table types) and
- row formats. For each table, you can decide which storage and
- indexing method to use. Choosing the proper table format for
- your application may give you a big performance gain. See
- <xref linkend="storage-engines"/>.
- </para>
-
- <para>
- You can get better performance for a table and minimize storage
- space by using the techniques listed here:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Use the most efficient (smallest) data types possible. MySQL
- has many specialized types that save disk space and memory.
- For example, use the smaller integer types if possible to
- get smaller tables. <literal role="type">MEDIUMINT</literal>
- is often a better choice than
- <literal role="type">INT</literal> because a
- <literal role="type">MEDIUMINT</literal> column uses 25%
- less space.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Declare columns to be <literal>NOT NULL</literal> if
- possible. It makes everything faster and you save one bit
- per column. If you really need <literal>NULL</literal> in
- your application, you should definitely use it. Just avoid
- having it on all columns by default.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For <literal>MyISAM</literal> tables, if you do not have any
- variable-length columns
- (<literal role="type">VARCHAR</literal>,
- <literal role="type">TEXT</literal>, or
- <literal role="type">BLOB</literal> columns), a fixed-size
- row format is used. This is faster but unfortunately may
- waste some space. See
- <xref linkend="myisam-table-formats"/>. You can hint that
- you want to have fixed length rows even if you have
- <literal role="type">VARCHAR</literal> columns with the
- <literal role="stmt">CREATE TABLE</literal> option
- <literal>ROW_FORMAT=FIXED</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>InnoDB</literal> tables use a compact storage
- format. In versions of MySQL earlier than 5.0.3,
- <literal>InnoDB</literal> rows contain some redundant
- information, such as the number of columns and the length of
- each column, even for fixed-size columns. By default, tables
- are created in the compact format
- (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
- downgrade to older versions of MySQL, you can request the
- old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
- </para>
-
- <para>
- The presence of the compact row format decreases row storage
- space by about 20% at the cost of increasing CPU use for
- some operations. If your workload is a typical one that is
- limited by cache hit rates and disk speed it is likely to be
- faster. If it is a rare case that is limited by CPU speed,
- it might be slower.
- </para>
-
- <para>
- The compact <literal>InnoDB</literal> format also changes
- how <literal role="type">CHAR</literal> columns containing
- UTF-8 data are stored. With
- <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
- <literal>CHAR(<replaceable>N</replaceable>)</literal>
- occupies 3 × <replaceable>N</replaceable> bytes, given
- that the maximum length of a UTF-8 encoded character is
- three bytes. Many languages can be written primarily using
- single-byte UTF-8 characters, so a fixed storage length
- often wastes space. With
- <literal>ROW_FORMAT=COMPACT</literal> format,
- <literal>InnoDB</literal> allocates a variable amount of
- storage in the range from <replaceable>N</replaceable> to 3
- × <replaceable>N</replaceable> bytes for these columns
- by stripping trailing spaces if necessary. The minimum
- storage length is kept as <replaceable>N</replaceable> bytes
- to facilitate in-place updates in typical cases.
- </para>
- </listitem>
-
- <listitem>
- <para>
- The primary index of a table should be as short as possible.
- This makes identification of each row easy and efficient.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Create only the indexes that you really need. Indexes are
- good for retrieval but bad when you need to store data
- quickly. If you access a table mostly by searching on a
- combination of columns, create an index on them. The first
- part of the index should be the column most used. If you
- <emphasis>always</emphasis> use many columns when selecting
- from the table, the first column in the index should be the
- one with the most duplicates to obtain better compression of
- the index.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If it is very likely that a string column has a unique
- prefix on the first number of characters, it is better to
- index only this prefix, using MySQL's support for creating
- an index on the leftmost part of the column (see
- <xref linkend="create-index"/>). Shorter indexes are faster,
- not only because they require less disk space, but because
- they also give you more hits in the index cache, and thus
- fewer disk seeks. See <xref linkend="server-parameters"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- In some circumstances, it can be beneficial to split into
- two a table that is scanned very often. This is especially
- true if it is a dynamic-format table and it is possible to
- use a smaller static format table that can be used to find
- the relevant rows when scanning the table.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="indexes">
-
<title>Column Indexes</title>
<indexterm>
@@ -9909,7 +8787,7 @@
MySQL can create composite indexes (that is, indexes on multiple
columns). An index may consist of up to 16 columns. For certain
data types, you can index a prefix of the column (see
- <xref linkend="indexes"/>).
+ <xref linkend="column-indexes"/>).
</para>
<para>
@@ -11613,6 +10491,1134 @@
</section>
+ </section>
+
+ <section id="locking-issues">
+
+ <title>Locking Issues</title>
+
+ <para>
+ MySQL manages contention for table contents using locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Internal locking is performed within the MySQL server itself
+ to manage contention for table contents by multiple threads.
+ This type of locking is internal because it is performed
+ entirely by the server and involves no other programs. See
+ <xref linkend="internal-locking"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ External locking occurs when the server and other programs
+ lock table files to coordinate among themselves which program
+ can access the tables at which time. See
+ <xref linkend="external-locking"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <section id="internal-locking">
+
+ <title>Internal Locking Methods</title>
+
+ <indexterm>
+ <primary>internal locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>internal</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking methods</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>methods</primary>
+ <secondary>locking</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>table-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>row-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>table-level</secondary>
+ </indexterm>
+
+ <para>
+ This section discusses internal locking; that is, locking
+ performed within the MySQL server itself to manage contention
+ for table contents by multiple sessions. This type of locking is
+ internal because it is performed entirely by the server and
+ involves no other programs. External locking occurs when the
+ server and other programs lock table files to coordinate among
+ themselves which program can access the tables at which time.
+ See <xref linkend="external-locking"/>.
+ </para>
+
+ <para>
+ MySQL uses table-level locking for <literal>MyISAM</literal>,
+ <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
+ and row-level locking for <literal>InnoDB</literal> tables.
+ </para>
+
+ <para>
+ In many cases, you can make an educated guess about which
+ locking type is best for an application, but generally it is
+ difficult to say that a given lock type is better than another.
+ Everything depends on the application and different parts of an
+ application may require different lock types.
+ </para>
+
+ <para>
+ To decide whether you want to use a storage engine with
+ row-level locking, you should look at what your application does
+ and what mix of select and update statements it uses. For
+ example, most Web applications perform many selects, relatively
+ few deletes, updates based mainly on key values, and inserts
+ into a few specific tables. The base MySQL
+ <literal>MyISAM</literal> setup is very well tuned for this.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ The MySQL Enterprise Monitor provides expert advice on when to
+ use table-level locking and when to use row-level locking. To
+ subscribe, see &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+
+ <para>
+ Table locking in MySQL is deadlock-free for storage engines that
+ use table-level locking. Deadlock avoidance is managed by always
+ requesting all needed locks at once at the beginning of a query
+ and always locking the tables in the same order.
+ </para>
+
+ <para>
+ MySQL grants table write locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no locks on the table, put a write lock on it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the write lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ MySQL grants table read locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no write locks on the table, put a read lock on
+ it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the read lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ Table updates are given higher priority than table retrievals.
+ Therefore, when a lock is released, the lock is made available
+ to the requests in the write lock queue and then to the requests
+ in the read lock queue. This ensures that updates to a table are
+ not <quote>starved</quote> even if there is heavy
+ <literal role="stmt">SELECT</literal> activity for the table.
+ However, if you have many updates for a table,
+ <literal role="stmt">SELECT</literal> statements wait until
+ there are no more updates.
+ </para>
+
+ <para>
+ For information on altering the priority of reads and writes,
+ see <xref linkend="table-locking"/>.
+ </para>
+
+ <para>
+ You can analyze the table lock contention on your system by
+ checking the
+ <literal role="statvar">Table_locks_immediate</literal> and
+ <literal role="statvar">Table_locks_waited</literal> status
+ variables, which indicate the number of times that requests for
+ table locks could be granted immediately and the number that had
+ to wait, respectively:
+ </para>
+
+<programlisting>
+mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
++-----------------------+---------+
+| Variable_name | Value |
++-----------------------+---------+
+| Table_locks_immediate | 1151552 |
+| Table_locks_waited | 15324 |
++-----------------------+---------+
+</programlisting>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no free
+ blocks in the middle of the data file, rows are always inserted
+ at the end of the data file. In this case, you can freely mix
+ concurrent <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> statements for a
+ <literal>MyISAM</literal> table without locks. That is, you can
+ insert rows into a <literal>MyISAM</literal> table at the same
+ time other clients are reading from it. Holes can result from
+ rows having been deleted from or updated in the middle of the
+ table. If there are holes, concurrent inserts are disabled but
+ are enabled again automatically when all holes have been filled
+ with new data.. This behavior is altered by the
+ <literal role="sysvar">concurrent_insert</literal> system
+ variable. See <xref linkend="concurrent-inserts"/>.
+ </para>
+
+ <para>
+ If you acquire a table lock explicitly with
+ <literal role="stmt">LOCK TABLES</literal>, you can request a
+ <literal>READ LOCAL</literal> lock rather than a
+ <literal>READ</literal> lock to enable other sessions to perform
+ concurrent inserts while you have the table locked.
+ </para>
+
+ <para>
+ To perform many <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> operations on a table
+ <literal>real_table</literal> when concurrent inserts are not
+ possible, you can insert rows into a temporary table
+ <literal>temp_table</literal> and update the real table with the
+ rows from the temporary table periodically. This can be done
+ with the following code:
+ </para>
+
+<programlisting>
+mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
+mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
+mysql> <userinput>DELETE FROM temp_table;</userinput>
+mysql> <userinput>UNLOCK TABLES;</userinput>
+</programlisting>
+
+ <para>
+ <literal>InnoDB</literal> uses row locks. Deadlocks are possible
+ for <literal>InnoDB</literal> because it automatically acquires
+ locks during the processing of SQL statements, not at the start
+ of the transaction.
+ </para>
+
+ <para>
+ Advantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Fewer lock conflicts when different sessions access
+ different rows
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fewer changes for rollbacks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Possible to lock a single row for a long time
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Disadvantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Requires more memory than table-level locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than table-level locks when used on a large part of
+ the table because you must acquire many more locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than other locks if you often do <literal>GROUP
+ BY</literal> operations on a large part of the data or if
+ you must scan the entire table frequently
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Generally, table locks are superior to row-level locks in the
+ following cases:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Most statements for the table are reads
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Statements for the table are a mix of reads and writes,
+ where writes are updates or deletes for a single row that
+ can be fetched with one key read:
+ </para>
+
+<programlisting>
+UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal role="stmt">SELECT</literal> combined with
+ concurrent <literal role="stmt">INSERT</literal> statements,
+ and very few <literal role="stmt">UPDATE</literal> or
+ <literal role="stmt">DELETE</literal> statements
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Many scans or <literal>GROUP BY</literal> operations on the
+ entire table without any writers
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With higher-level locks, you can more easily tune applications
+ by supporting locks of different types, because the lock
+ overhead is less than for row-level locks.
+ </para>
+
+ <para>
+ Options other than row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Versioning (such as that used in MySQL for concurrent
+ inserts) where it is possible to have one writer at the same
+ time as many readers. This means that the database or table
+ supports different views for the data depending on when
+ access begins. Other common terms for this are <quote>time
+ travel,</quote> <quote>copy on write,</quote> or <quote>copy
+ on demand.</quote>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Copy on demand is in many cases superior to row-level
+ locking. However, in the worst case, it can use much more
+ memory than using normal locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Instead of using row-level locks, you can employ
+ application-level locks, such as those provided by
+ <literal role="func">GET_LOCK()</literal> and
+ <literal role="func">RELEASE_LOCK()</literal> in MySQL.
+ These are advisory locks, so they work only with
+ applications that cooperate with each other. See
+ <xref linkend="miscellaneous-functions"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="table-locking">
+
+ <title>Table Locking Issues</title>
+
+ <indexterm>
+ <primary>problems</primary>
+ <secondary>table locking</secondary>
+ </indexterm>
+
+ <para>
+ To achieve a very high lock speed, MySQL uses table locking
+ (instead of page, row, or column locking) for all storage
+ engines except <literal>InnoDB</literal> and
+ <literal role="se">NDBCLUSTER</literal>.
+ </para>
+
+ <para>
+ For <literal>InnoDB</literal> tables, MySQL uses table locking
+ only if you explicitly lock the table with
+ <literal role="stmt">LOCK TABLES</literal>. For this storage
+ engine, avoid using <literal role="stmt">LOCK TABLES</literal>
+ at all, because <literal>InnoDB</literal> uses automatic
+ row-level locking to ensure transaction isolation.
+ </para>
+
+ <para>
+ For large tables, table locking is often better than row
+ locking, but there are some disadvantages:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Table locking enables many sessions to read from a table at
+ the same time, but if a session wants to write to a table,
+ it must first get exclusive access. During the update, all
+ other sessions that want to access this particular table
+ must wait until the update is done.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Table locking causes problems in cases such as when a
+ session is waiting because the disk is full and free space
+ needs to become available before the session can proceed. In
+ this case, all sessions that want to access the problem
+ table are also put in a waiting state until more disk space
+ is made available.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Table locking is also disadvantageous under the following
+ scenario:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ A session issues a <literal role="stmt">SELECT</literal>
+ that takes a long time to run.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session then issues an
+ <literal role="stmt">UPDATE</literal> on the same table.
+ This session waits until the
+ <literal role="stmt">SELECT</literal> is finished.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session issues another
+ <literal role="stmt">SELECT</literal> statement on the same
+ table. Because <literal role="stmt">UPDATE</literal> has
+ higher priority than <literal role="stmt">SELECT</literal>,
+ this <literal role="stmt">SELECT</literal> waits for the
+ <literal role="stmt">UPDATE</literal> to finish,
+ <emphasis>after</emphasis> waiting for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following items describe some ways to avoid or reduce
+ contention caused by table locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Try to get the <literal role="stmt">SELECT</literal>
+ statements to run faster so that they lock tables for a
+ shorter time. You might have to create some summary tables
+ to do this.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with
+ <option role="mysqld">--low-priority-updates</option>. For
+ storage engines that use only table-level locking (such as
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
+ <literal>MERGE</literal>), this gives all statements that
+ update (modify) a table lower priority than
+ <literal role="stmt">SELECT</literal> statements. In this
+ case, the second <literal role="stmt">SELECT</literal>
+ statement in the preceding scenario would execute before the
+ <literal role="stmt">UPDATE</literal> statement, and would
+ not need to wait for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To specify that all updates issued in a specific connection
+ should be done with low priority, set the
+ <literal role="sysvar">low_priority_updates</literal> server
+ system variable equal to 1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">INSERT</literal>,
+ <literal role="stmt">UPDATE</literal>, or
+ <literal role="stmt">DELETE</literal> statement lower
+ priority, use the <literal>LOW_PRIORITY</literal> attribute.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">SELECT</literal>
+ statement higher priority, use the
+ <literal>HIGH_PRIORITY</literal> attribute. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with a low value for the
+ <literal role="sysvar">max_write_lock_count</literal> system
+ variable to force MySQL to temporarily elevate the priority
+ of all <literal role="stmt">SELECT</literal> statements that
+ are waiting for a table after a specific number of inserts
+ to the table occur. This permits <literal>READ</literal>
+ locks after a certain number of <literal>WRITE</literal>
+ locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with
+ <literal role="stmt">INSERT</literal> combined with
+ <literal role="stmt">SELECT</literal>, consider switching to
+ <literal>MyISAM</literal> tables, which support concurrent
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">INSERT</literal> statements. (See
+ <xref linkend="concurrent-inserts"/>.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you mix inserts and deletes on the same table,
+ <literal role="stmt">INSERT DELAYED</literal> may be of
+ great help. See <xref linkend="insert-delayed"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with mixed
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">DELETE</literal> statements, the
+ <literal>LIMIT</literal> option to
+ <literal role="stmt">DELETE</literal> may help. See
+ <xref linkend="delete"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Using <literal>SQL_BUFFER_RESULT</literal> with
+ <literal role="stmt">SELECT</literal> statements can help to
+ make the duration of table locks shorter. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You could change the locking code in
+ <filename>mysys/thr_lock.c</filename> to use a single queue.
+ In this case, write locks and read locks would have the same
+ priority, which might help some applications.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Here are some tips concerning table locks in MySQL:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Concurrent users are not a problem if you do not mix updates
+ with selects that need to examine many rows in the same
+ table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can use <literal role="stmt">LOCK TABLES</literal> to
+ increase speed, because many updates within a single lock is
+ much faster than updating without locks. Splitting table
+ contents into separate tables may also help.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you encounter speed problems with table locks in MySQL,
+ you may be able to improve performance by converting some of
+ your tables to <literal>InnoDB</literal>. See
+ <xref linkend="innodb"/>.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ Lock contention can seriously degrade performance. The
+ MySQL Enterprise Monitor provides expert advice on
+ avoiding this problem. To subscribe, see
+ &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="concurrent-inserts">
+
+ <title>Concurrent Inserts</title>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no holes
+ in the data file (deleted rows in the middle), an
+ <literal role="stmt">INSERT</literal> statement can be executed
+ to add rows to the end of the table at the same time that
+ <literal role="stmt">SELECT</literal> statements are reading
+ rows from the table. If there are multiple
+ <literal role="stmt">INSERT</literal> statements, they are
+ queued and performed in sequence, concurrently with the
+ <literal role="stmt">SELECT</literal> statements. The results of
+ a concurrent <literal role="stmt">INSERT</literal> may not be
+ visible immediately.
+ </para>
+
+ <para>
+ The <literal role="sysvar">concurrent_insert</literal> system
+ variable can be set to modify the concurrent-insert processing.
+ By default, the variable is set to 1 and concurrent inserts are
+ handled as just described. If
+ <literal role="sysvar">concurrent_insert</literal> is set to 0,
+ concurrent inserts are disabled. If the variable is set to 2,
+ concurrent inserts at the end of the table are allowed even for
+ tables that have deleted rows. See also the description of the
+ <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
+ system variable.
+ </para>
+
+ <para>
+ Under circumstances where concurrent inserts can be used, there
+ is seldom any need to use the <literal>DELAYED</literal>
+ modifier for <literal role="stmt">INSERT</literal> statements.
+ See <xref linkend="insert-delayed"/>.
+ </para>
+
+ <para>
+ If you are using the binary log, concurrent inserts are
+ converted to normal inserts for <literal>CREATE ...
+ SELECT</literal> or
+ <literal role="stmt" condition="insert-select">INSERT ...
+ SELECT</literal> statements. This is done to ensure that you can
+ re-create an exact copy of your tables by applying the log
+ during a backup operation. See <xref linkend="binary-log"/>. In
+ addition, for those statements a read lock is placed on the
+ selected-from table such that inserts into that table are
+ blocked. The effect is that concurrent inserts for that table
+ must wait as well.
+ </para>
+
+ <para>
+ With <literal role="stmt" condition="load-data">LOAD DATA
+ INFILE</literal>, if you specify <literal>CONCURRENT</literal>
+ with a <literal>MyISAM</literal> table that satisfies the
+ condition for concurrent inserts (that is, it contains no free
+ blocks in the middle), other sessions can retrieve data from the
+ table while <literal role="stmt">LOAD DATA</literal> is
+ executing. Use of the <literal>CONCURRENT</literal> option
+ affects the performance of <literal role="stmt">LOAD
+ DATA</literal> a bit, even if no other session is using the
+ table at the same time.
+ </para>
+
+ <para>
+ If you specify <literal>HIGH_PRIORITY</literal>, it overrides
+ the effect of the
+ <option role="mysqld">--low-priority-updates</option> option if
+ the server was started with that option. It also causes
+ concurrent inserts not to be used.
+ </para>
+
+ <para>
+ For <literal role="stmt" condition="lock-tables">LOCK
+ TABLE</literal>, the difference between <literal>READ
+ LOCAL</literal> and <literal>READ</literal> is that
+ <literal>READ LOCAL</literal> permits nonconflicting
+ <literal role="stmt">INSERT</literal> statements (concurrent
+ inserts) to execute while the lock is held. However, this cannot
+ be used if you are going to manipulate the database using
+ processes external to the server while you hold the lock.
+ </para>
+
+ </section>
+
+ <section id="external-locking">
+
+ <title>External Locking</title>
+
+ <indexterm>
+ <primary>external locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>external</secondary>
+ </indexterm>
+
+ <para>
+ External locking is the use of file system locking to manage
+ contention for database tables by multiple processes. External
+ locking is used in situations where a single process such as the
+ MySQL server cannot be assumed to be the only process that
+ requires access to tables. Here are some examples:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ If you run multiple servers that use the same database
+ directory (not recommended), each server must have external
+ locking enabled.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you use <command>myisamchk</command> to perform table
+ maintenance operations on <literal>MyISAM</literal> tables,
+ you must either ensure that the server is not running, or
+ that the server has external locking enabled so that it
+ locks table files as necessary to coordinate with
+ <command>myisamchk</command> for access to the tables. The
+ same is true for use of <command>myisampack</command> to
+ pack <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ If the server is run with external locking enabled, you can
+ use <command>myisamchk</command> at any time for read
+ operations such a checking tables. In this case, if the
+ server tries to update a table that
+ <command>myisamchk</command> is using, the server will wait
+ for <command>myisamchk</command> to finish before it
+ continues.
+ </para>
+
+ <para>
+ If you use <command>myisamchk</command> for write operations
+ such as repairing or optimizing tables, or if you use
+ <command>myisampack</command> to pack tables, you
+ <emphasis>must</emphasis> always ensure that the
+ <command>mysqld</command> server is not using the table. If
+ you don't stop <command>mysqld</command>, you should at
+ least do a <command>mysqladmin flush-tables</command> before
+ you run <command>myisamchk</command>. Your tables
+ <emphasis>may become corrupted</emphasis> if the server and
+ <command>myisamchk</command> access the tables
+ simultaneously.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With external locking in effect, each process that requires
+ access to a table acquires a file system lock for the table
+ files before proceeding to access the table. If all necessary
+ locks cannot be acquired, the process is blocked from accessing
+ the table until the locks can be obtained (after the process
+ that currently holds the locks releases them).
+ </para>
+
+ <para>
+ External locking affects server performance because the server
+ must sometimes wait for other processes before it can access
+ tables.
+ </para>
+
+ <para>
+ External locking is unnecessary if you run a single server to
+ access a given data directory (which is the usual case) and if
+ no other programs such as <command>myisamchk</command> need to
+ modify tables while the server is running. If you only
+ <emphasis>read</emphasis> tables with other programs, external
+ locking is not required, although <command>myisamchk</command>
+ might report warnings if the server changes tables while
+ <command>myisamchk</command> is reading them.
+ </para>
+
+ <para>
+ With external locking disabled, to use
+ <command>myisamchk</command>, you must either stop the server
+ while <command>myisamchk</command> executes or else lock and
+ flush the tables before running <command>myisamchk</command>.
+ (See <xref linkend="system-optimization"/>.) To avoid this
+ requirement, use the <literal role="stmt">CHECK TABLE</literal>
+ and <literal role="stmt">REPAIR TABLE</literal> statements to
+ check and repair <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ For <command>mysqld</command>, external locking is controlled by
+ the value of the
+ <literal role="sysvar">skip_external_locking</literal> system
+ variable. When this variable is enabled, external locking is
+ disabled, and vice versa. From MySQL 4.0 on, external locking is
+ disabled by default. Before MySQL 4.0, external locking is
+ enabled by default on Linux or when MySQL is configured to use
+ MIT-pthreads.
+ </para>
+
+ <para>
+ Use of external locking can be controlled at server startup by
+ using the <option role="mysqld">--external-locking</option> or
+ <option role="mysqld">--skip-external-locking</option> option.
+ </para>
+
+ <para>
+ If you do use external locking option to enable updates to
+ <literal>MyISAM</literal> tables from many MySQL processes, you
+ must ensure that the following conditions are satisfied:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ You should not use the query cache for queries that use
+ tables that are updated by another process.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You should not start the server with the
+ <option role="mysqld">--delay-key-write=ALL</option> option
+ or use the <literal>DELAY_KEY_WRITE=1</literal> table option
+ for any shared tables. Otherwise, index corruption can
+ occur.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The easiest way to satisfy these conditions is to always use
+ <option role="mysqld">--external-locking</option> together with
+ <option role="mysqld">--delay-key-write=OFF</option> and
+ <option role="sysvar">--query-cache-size=0</option>. (This is
+ not done by default because in many setups it is useful to have
+ a mixture of the preceding options.)
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="optimizing-database-structure">
+
+ <title>Optimizing Database Structure</title>
+
+ <section id="data-size">
+
+ <title>Make Your Data as Small as Possible</title>
+
+ <indexterm>
+ <primary>data</primary>
+ <secondary>size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>reducing</primary>
+ <secondary>data size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>storage space</primary>
+ <secondary>minimizing</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>tables</primary>
+ <secondary>improving performance</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>performance</primary>
+ <secondary>improving</secondary>
+ </indexterm>
+
+ <para>
+ One of the most basic optimizations is to design your tables to
+ take as little space on the disk as possible. This can result in
+ huge improvements because disk reads are faster, and smaller
+ tables normally require less main memory while their contents
+ are being actively processed during query execution. Indexing
+ also is a lesser resource burden if done on smaller columns.
+ </para>
+
+ <para>
+ MySQL supports many different storage engines (table types) and
+ row formats. For each table, you can decide which storage and
+ indexing method to use. Choosing the proper table format for
+ your application may give you a big performance gain. See
+ <xref linkend="storage-engines"/>.
+ </para>
+
+ <para>
+ You can get better performance for a table and minimize storage
+ space by using the techniques listed here:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Use the most efficient (smallest) data types possible. MySQL
+ has many specialized types that save disk space and memory.
+ For example, use the smaller integer types if possible to
+ get smaller tables. <literal role="type">MEDIUMINT</literal>
+ is often a better choice than
+ <literal role="type">INT</literal> because a
+ <literal role="type">MEDIUMINT</literal> column uses 25%
+ less space.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Declare columns to be <literal>NOT NULL</literal> if
+ possible. It makes everything faster and you save one bit
+ per column. If you really need <literal>NULL</literal> in
+ your application, you should definitely use it. Just avoid
+ having it on all columns by default.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For <literal>MyISAM</literal> tables, if you do not have any
+ variable-length columns
+ (<literal role="type">VARCHAR</literal>,
+ <literal role="type">TEXT</literal>, or
+ <literal role="type">BLOB</literal> columns), a fixed-size
+ row format is used. This is faster but unfortunately may
+ waste some space. See
+ <xref linkend="myisam-table-formats"/>. You can hint that
+ you want to have fixed length rows even if you have
+ <literal role="type">VARCHAR</literal> columns with the
+ <literal role="stmt">CREATE TABLE</literal> option
+ <literal>ROW_FORMAT=FIXED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>InnoDB</literal> tables use a compact storage
+ format. In versions of MySQL earlier than 5.0.3,
+ <literal>InnoDB</literal> rows contain some redundant
+ information, such as the number of columns and the length of
+ each column, even for fixed-size columns. By default, tables
+ are created in the compact format
+ (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
+ downgrade to older versions of MySQL, you can request the
+ old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
+ </para>
+
+ <para>
+ The presence of the compact row format decreases row storage
+ space by about 20% at the cost of increasing CPU use for
+ some operations. If your workload is a typical one that is
+ limited by cache hit rates and disk speed it is likely to be
+ faster. If it is a rare case that is limited by CPU speed,
+ it might be slower.
+ </para>
+
+ <para>
+ The compact <literal>InnoDB</literal> format also changes
+ how <literal role="type">CHAR</literal> columns containing
+ UTF-8 data are stored. With
+ <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
+ <literal>CHAR(<replaceable>N</replaceable>)</literal>
+ occupies 3 × <replaceable>N</replaceable> bytes, given
+ that the maximum length of a UTF-8 encoded character is
+ three bytes. Many languages can be written primarily using
+ single-byte UTF-8 characters, so a fixed storage length
+ often wastes space. With
+ <literal>ROW_FORMAT=COMPACT</literal> format,
+ <literal>InnoDB</literal> allocates a variable amount of
+ storage in the range from <replaceable>N</replaceable> to 3
+ × <replaceable>N</replaceable> bytes for these columns
+ by stripping trailing spaces if necessary. The minimum
+ storage length is kept as <replaceable>N</replaceable> bytes
+ to facilitate in-place updates in typical cases.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The primary index of a table should be as short as possible.
+ This makes identification of each row easy and efficient.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create only the indexes that you really need. Indexes are
+ good for retrieval but bad when you need to store data
+ quickly. If you access a table mostly by searching on a
+ combination of columns, create an index on them. The first
+ part of the index should be the column most used. If you
+ <emphasis>always</emphasis> use many columns when selecting
+ from the table, the first column in the index should be the
+ one with the most duplicates to obtain better compression of
+ the index.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If it is very likely that a string column has a unique
+ prefix on the first number of characters, it is better to
+ index only this prefix, using MySQL's support for creating
+ an index on the leftmost part of the column (see
+ <xref linkend="create-index"/>). Shorter indexes are faster,
+ not only because they require less disk space, but because
+ they also give you more hits in the index cache, and thus
+ fewer disk seeks. See <xref linkend="server-parameters"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ In some circumstances, it can be beneficial to split into
+ two a table that is scanned very often. This is especially
+ true if it is a dynamic-format table and it is possible to
+ use a smaller static format table that can be used to find
+ the relevant rows when scanning the table.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
<section id="table-cache">
<title>How MySQL Opens and Closes Tables</title>
Modified: trunk/refman-5.1/renamed-nodes.txt
===================================================================
--- trunk/refman-5.1/renamed-nodes.txt 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.1/renamed-nodes.txt 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 0; 660 bytes
@@ -45,6 +45,7 @@
events-limitations-restrictions stored-program-restrictions 2009-09-19
german-character-set charset-we-sets 2010-08-08
group-by-hidden-fields group-by-hidden-columns 2010-01-01
+indexes column-indexes 2011-07-14
innodb-and-autocommit innodb-transaction-model 2009-11-24
innodb-consistent-read-example innodb-consistent-read 2010-03-10
innodb-general-monitor innodb-monitors 2010-11-05
Modified: trunk/refman-5.1/sql-syntax-data-definition.xml
===================================================================
--- trunk/refman-5.1/sql-syntax-data-definition.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.1/sql-syntax-data-definition.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 663 bytes
@@ -5939,7 +5939,7 @@
<literal role="type">VARBINARY</literal>, and
<literal role="type">BLOB</literal> columns. Indexing only a
prefix of column values like this can make the index file much
- smaller. See <xref linkend="indexes"/>.
+ smaller. See <xref linkend="column-indexes"/>.
</para>
<indexterm>
Modified: trunk/refman-5.5/data-types.xml
===================================================================
--- trunk/refman-5.5/data-types.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.5/data-types.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 594 bytes
@@ -4643,7 +4643,7 @@
specify an index prefix length. For
<literal role="type">CHAR</literal> and
<literal role="type">VARCHAR</literal>, a prefix length is
- optional. See <xref linkend="indexes"/>.
+ optional. See <xref linkend="column-indexes"/>.
</para>
</listitem>
Modified: trunk/refman-5.5/optimization.xml
===================================================================
--- trunk/refman-5.5/optimization.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.5/optimization.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 3, Lines Added: 1194, Lines Deleted: 1188; 88249 bytes
@@ -8761,1196 +8761,12 @@
</section>
- <section id="locking-issues">
+ <section id="optimization-indexes">
- <title>Locking Issues</title>
+ <title>Optimization and Indexes</title>
- <para>
- MySQL manages contention for table contents using locking:
- </para>
+ <section id="column-indexes">
- <itemizedlist>
-
- <listitem>
- <para>
- Internal locking is performed within the MySQL server itself
- to manage contention for table contents by multiple threads.
- This type of locking is internal because it is performed
- entirely by the server and involves no other programs. See
- <xref linkend="internal-locking"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- External locking occurs when the server and other programs
- lock table files to coordinate among themselves which program
- can access the tables at which time. See
- <xref linkend="external-locking"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <section id="internal-locking">
-
- <title>Internal Locking Methods</title>
-
- <indexterm>
- <primary>internal locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>internal</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking methods</primary>
- </indexterm>
-
- <indexterm>
- <primary>methods</primary>
- <secondary>locking</secondary>
- </indexterm>
-
- <indexterm>
- <primary>row-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>table-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>row-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>table-level</secondary>
- </indexterm>
-
- <para>
- This section discusses internal locking; that is, locking
- performed within the MySQL server itself to manage contention
- for table contents by multiple sessions. This type of locking is
- internal because it is performed entirely by the server and
- involves no other programs. External locking occurs when the
- server and other programs lock table files to coordinate among
- themselves which program can access the tables at which time.
- See <xref linkend="external-locking"/>.
- </para>
-
- <para>
- MySQL uses table-level locking for <literal>MyISAM</literal>,
- <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
- and row-level locking for <literal>InnoDB</literal> tables.
- </para>
-
- <para>
- In many cases, you can make an educated guess about which
- locking type is best for an application, but generally it is
- difficult to say that a given lock type is better than another.
- Everything depends on the application and different parts of an
- application may require different lock types.
- </para>
-
- <para>
- To decide whether you want to use a storage engine with
- row-level locking, you should look at what your application does
- and what mix of select and update statements it uses. For
- example, most Web applications perform many selects, relatively
- few deletes, updates based mainly on key values, and inserts
- into a few specific tables. The base MySQL
- <literal>MyISAM</literal> setup is very well tuned for this.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- The MySQL Enterprise Monitor provides expert advice on when to
- use table-level locking and when to use row-level locking. To
- subscribe, see &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
-
- <para>
- Table locking in MySQL is deadlock-free for storage engines that
- use table-level locking. Deadlock avoidance is managed by always
- requesting all needed locks at once at the beginning of a query
- and always locking the tables in the same order.
- </para>
-
- <para>
- MySQL grants table write locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no locks on the table, put a write lock on it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the write lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- MySQL grants table read locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no write locks on the table, put a read lock on
- it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the read lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- Table updates are given higher priority than table retrievals.
- Therefore, when a lock is released, the lock is made available
- to the requests in the write lock queue and then to the requests
- in the read lock queue. This ensures that updates to a table are
- not <quote>starved</quote> even if there is heavy
- <literal role="stmt">SELECT</literal> activity for the table.
- However, if you have many updates for a table,
- <literal role="stmt">SELECT</literal> statements wait until
- there are no more updates.
- </para>
-
- <para>
- For information on altering the priority of reads and writes,
- see <xref linkend="table-locking"/>.
- </para>
-
- <para>
- You can analyze the table lock contention on your system by
- checking the
- <literal role="statvar">Table_locks_immediate</literal> and
- <literal role="statvar">Table_locks_waited</literal> status
- variables, which indicate the number of times that requests for
- table locks could be granted immediately and the number that had
- to wait, respectively:
- </para>
-
-<programlisting>
-mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
-+-----------------------+---------+
-| Variable_name | Value |
-+-----------------------+---------+
-| Table_locks_immediate | 1151552 |
-| Table_locks_waited | 15324 |
-+-----------------------+---------+
-</programlisting>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no free
- blocks in the middle of the data file, rows are always inserted
- at the end of the data file. In this case, you can freely mix
- concurrent <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> statements for a
- <literal>MyISAM</literal> table without locks. That is, you can
- insert rows into a <literal>MyISAM</literal> table at the same
- time other clients are reading from it. Holes can result from
- rows having been deleted from or updated in the middle of the
- table. If there are holes, concurrent inserts are disabled but
- are enabled again automatically when all holes have been filled
- with new data.. This behavior is altered by the
- <literal role="sysvar">concurrent_insert</literal> system
- variable. See <xref linkend="concurrent-inserts"/>.
- </para>
-
- <para>
- If you acquire a table lock explicitly with
- <literal role="stmt">LOCK TABLES</literal>, you can request a
- <literal>READ LOCAL</literal> lock rather than a
- <literal>READ</literal> lock to enable other sessions to perform
- concurrent inserts while you have the table locked.
- </para>
-
- <para>
- To perform many <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> operations on a table
- <literal>real_table</literal> when concurrent inserts are not
- possible, you can insert rows into a temporary table
- <literal>temp_table</literal> and update the real table with the
- rows from the temporary table periodically. This can be done
- with the following code:
- </para>
-
-<programlisting>
-mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
-mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
-mysql> <userinput>DELETE FROM temp_table;</userinput>
-mysql> <userinput>UNLOCK TABLES;</userinput>
-</programlisting>
-
- <para>
- <literal>InnoDB</literal> uses row locks. Deadlocks are possible
- for <literal>InnoDB</literal> because it automatically acquires
- locks during the processing of SQL statements, not at the start
- of the transaction.
- </para>
-
- <para>
- Advantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Fewer lock conflicts when different sessions access
- different rows
- </para>
- </listitem>
-
- <listitem>
- <para>
- Fewer changes for rollbacks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Possible to lock a single row for a long time
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Disadvantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Requires more memory than table-level locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than table-level locks when used on a large part of
- the table because you must acquire many more locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than other locks if you often do <literal>GROUP
- BY</literal> operations on a large part of the data or if
- you must scan the entire table frequently
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Generally, table locks are superior to row-level locks in the
- following cases:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Most statements for the table are reads
- </para>
- </listitem>
-
- <listitem>
- <para>
- Statements for the table are a mix of reads and writes,
- where writes are updates or deletes for a single row that
- can be fetched with one key read:
- </para>
-
-<programlisting>
-UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-</programlisting>
- </listitem>
-
- <listitem>
- <para>
- <literal role="stmt">SELECT</literal> combined with
- concurrent <literal role="stmt">INSERT</literal> statements,
- and very few <literal role="stmt">UPDATE</literal> or
- <literal role="stmt">DELETE</literal> statements
- </para>
- </listitem>
-
- <listitem>
- <para>
- Many scans or <literal>GROUP BY</literal> operations on the
- entire table without any writers
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With higher-level locks, you can more easily tune applications
- by supporting locks of different types, because the lock
- overhead is less than for row-level locks.
- </para>
-
- <para>
- Options other than row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Versioning (such as that used in MySQL for concurrent
- inserts) where it is possible to have one writer at the same
- time as many readers. This means that the database or table
- supports different views for the data depending on when
- access begins. Other common terms for this are <quote>time
- travel,</quote> <quote>copy on write,</quote> or <quote>copy
- on demand.</quote>
- </para>
- </listitem>
-
- <listitem>
- <para>
- Copy on demand is in many cases superior to row-level
- locking. However, in the worst case, it can use much more
- memory than using normal locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Instead of using row-level locks, you can employ
- application-level locks, such as those provided by
- <literal role="func">GET_LOCK()</literal> and
- <literal role="func">RELEASE_LOCK()</literal> in MySQL.
- These are advisory locks, so they work only with
- applications that cooperate with each other. See
- <xref linkend="miscellaneous-functions"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="table-locking">
-
- <title>Table Locking Issues</title>
-
- <indexterm>
- <primary>problems</primary>
- <secondary>table locking</secondary>
- </indexterm>
-
- <para>
- To achieve a very high lock speed, MySQL uses table locking
- (instead of page, row, or column locking) for all storage
- engines except <literal>InnoDB</literal>.
- </para>
-
- <para>
- For <literal>InnoDB</literal> tables, MySQL uses table locking
- only if you explicitly lock the table with
- <literal role="stmt">LOCK TABLES</literal>. For this storage
- engine, avoid using <literal role="stmt">LOCK TABLES</literal>
- at all, because <literal>InnoDB</literal> uses automatic
- row-level locking to ensure transaction isolation.
- </para>
-
- <para>
- For large tables, table locking is often better than row
- locking, but there are some disadvantages:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Table locking enables many sessions to read from a table at
- the same time, but if a session wants to write to a table,
- it must first get exclusive access. During the update, all
- other sessions that want to access this particular table
- must wait until the update is done.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Table locking causes problems in cases such as when a
- session is waiting because the disk is full and free space
- needs to become available before the session can proceed. In
- this case, all sessions that want to access the problem
- table are also put in a waiting state until more disk space
- is made available.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Table locking is also disadvantageous under the following
- scenario:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A session issues a <literal role="stmt">SELECT</literal>
- that takes a long time to run.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session then issues an
- <literal role="stmt">UPDATE</literal> on the same table.
- This session waits until the
- <literal role="stmt">SELECT</literal> is finished.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session issues another
- <literal role="stmt">SELECT</literal> statement on the same
- table. Because <literal role="stmt">UPDATE</literal> has
- higher priority than <literal role="stmt">SELECT</literal>,
- this <literal role="stmt">SELECT</literal> waits for the
- <literal role="stmt">UPDATE</literal> to finish,
- <emphasis>after</emphasis> waiting for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following items describe some ways to avoid or reduce
- contention caused by table locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Try to get the <literal role="stmt">SELECT</literal>
- statements to run faster so that they lock tables for a
- shorter time. You might have to create some summary tables
- to do this.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with
- <option role="mysqld">--low-priority-updates</option>. For
- storage engines that use only table-level locking (such as
- <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
- <literal>MERGE</literal>), this gives all statements that
- update (modify) a table lower priority than
- <literal role="stmt">SELECT</literal> statements. In this
- case, the second <literal role="stmt">SELECT</literal>
- statement in the preceding scenario would execute before the
- <literal role="stmt">UPDATE</literal> statement, and would
- not need to wait for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To specify that all updates issued in a specific connection
- should be done with low priority, set the
- <literal role="sysvar">low_priority_updates</literal> server
- system variable equal to 1.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">INSERT</literal>,
- <literal role="stmt">UPDATE</literal>, or
- <literal role="stmt">DELETE</literal> statement lower
- priority, use the <literal>LOW_PRIORITY</literal> attribute.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">SELECT</literal>
- statement higher priority, use the
- <literal>HIGH_PRIORITY</literal> attribute. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with a low value for the
- <literal role="sysvar">max_write_lock_count</literal> system
- variable to force MySQL to temporarily elevate the priority
- of all <literal role="stmt">SELECT</literal> statements that
- are waiting for a table after a specific number of inserts
- to the table occur. This permits <literal>READ</literal>
- locks after a certain number of <literal>WRITE</literal>
- locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with
- <literal role="stmt">INSERT</literal> combined with
- <literal role="stmt">SELECT</literal>, consider switching to
- <literal>MyISAM</literal> tables, which support concurrent
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">INSERT</literal> statements. (See
- <xref linkend="concurrent-inserts"/>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you mix inserts and deletes on the same table,
- <literal role="stmt">INSERT DELAYED</literal> may be of
- great help. See <xref linkend="insert-delayed"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with mixed
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">DELETE</literal> statements, the
- <literal>LIMIT</literal> option to
- <literal role="stmt">DELETE</literal> may help. See
- <xref linkend="delete"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Using <literal>SQL_BUFFER_RESULT</literal> with
- <literal role="stmt">SELECT</literal> statements can help to
- make the duration of table locks shorter. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You could change the locking code in
- <filename>mysys/thr_lock.c</filename> to use a single queue.
- In this case, write locks and read locks would have the same
- priority, which might help some applications.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Here are some tips concerning table locks in MySQL:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Concurrent users are not a problem if you do not mix updates
- with selects that need to examine many rows in the same
- table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can use <literal role="stmt">LOCK TABLES</literal> to
- increase speed, because many updates within a single lock is
- much faster than updating without locks. Splitting table
- contents into separate tables may also help.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you encounter speed problems with table locks in MySQL,
- you may be able to improve performance by converting some of
- your tables to <literal>InnoDB</literal>. See
- <xref linkend="innodb"/>.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- Lock contention can seriously degrade performance. The
- MySQL Enterprise Monitor provides expert advice on
- avoiding this problem. To subscribe, see
- &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="concurrent-inserts">
-
- <title>Concurrent Inserts</title>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no holes
- in the data file (deleted rows in the middle), an
- <literal role="stmt">INSERT</literal> statement can be executed
- to add rows to the end of the table at the same time that
- <literal role="stmt">SELECT</literal> statements are reading
- rows from the table. If there are multiple
- <literal role="stmt">INSERT</literal> statements, they are
- queued and performed in sequence, concurrently with the
- <literal role="stmt">SELECT</literal> statements. The results of
- a concurrent <literal role="stmt">INSERT</literal> may not be
- visible immediately.
- </para>
-
- <para>
- The <literal role="sysvar">concurrent_insert</literal> system
- variable can be set to modify the concurrent-insert processing.
- By default, the variable is set to <literal>AUTO</literal> (or
- 1) and concurrent inserts are handled as just described. If
- <literal role="sysvar">concurrent_insert</literal> is set to
- <literal>NEVER</literal> (or 0), concurrent inserts are
- disabled. If the variable is set to <literal>ALWAYS</literal>
- (or 2), concurrent inserts at the end of the table are allowed
- even for tables that have deleted rows. See also the description
- of the
- <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
- system variable.
- </para>
-
- <para>
- Under circumstances where concurrent inserts can be used, there
- is seldom any need to use the <literal>DELAYED</literal>
- modifier for <literal role="stmt">INSERT</literal> statements.
- See <xref linkend="insert-delayed"/>.
- </para>
-
- <para>
- If you are using the binary log, concurrent inserts are
- converted to normal inserts for <literal>CREATE ...
- SELECT</literal> or
- <literal role="stmt" condition="insert-select">INSERT ...
- SELECT</literal> statements. This is done to ensure that you can
- re-create an exact copy of your tables by applying the log
- during a backup operation. See <xref linkend="binary-log"/>. In
- addition, for those statements a read lock is placed on the
- selected-from table such that inserts into that table are
- blocked. The effect is that concurrent inserts for that table
- must wait as well.
- </para>
-
- <para>
- With <literal role="stmt" condition="load-data">LOAD DATA
- INFILE</literal>, if you specify <literal>CONCURRENT</literal>
- with a <literal>MyISAM</literal> table that satisfies the
- condition for concurrent inserts (that is, it contains no free
- blocks in the middle), other sessions can retrieve data from the
- table while <literal role="stmt">LOAD DATA</literal> is
- executing. Use of the <literal>CONCURRENT</literal> option
- affects the performance of <literal role="stmt">LOAD
- DATA</literal> a bit, even if no other session is using the
- table at the same time.
- </para>
-
- <para>
- If you specify <literal>HIGH_PRIORITY</literal>, it overrides
- the effect of the
- <option role="mysqld">--low-priority-updates</option> option if
- the server was started with that option. It also causes
- concurrent inserts not to be used.
- </para>
-
- <para>
- For <literal role="stmt" condition="lock-tables">LOCK
- TABLE</literal>, the difference between <literal>READ
- LOCAL</literal> and <literal>READ</literal> is that
- <literal>READ LOCAL</literal> permits nonconflicting
- <literal role="stmt">INSERT</literal> statements (concurrent
- inserts) to execute while the lock is held. However, this cannot
- be used if you are going to manipulate the database using
- processes external to the server while you hold the lock.
- </para>
-
- </section>
-
- <section id="metadata-locking">
-
- <title>Metadata Locking Within Transactions</title>
-
- <indexterm>
- <primary>metadata locking</primary>
- <secondary>transactions</secondary>
- </indexterm>
-
- <indexterm>
- <primary>transactions</primary>
- <secondary>metadata locking</secondary>
- </indexterm>
-
- <para>
- To ensure transaction serializability, the server must not allow
- one session to perform a data definition language (DDL)
- statement on a table that is used in an uncompleted transaction
- in another session.
- </para>
-
- <para>
- As of MySQL 5.5.3, the server achieves this by acquiring
- metadata locks on tables used within a transaction and deferring
- release of those locks until the transaction ends. A metadata
- lock on a table prevents changes to the table's structure. This
- locking approach has the implication that a table that is being
- used by a transaction within one session cannot be used in DDL
- statements by other sessions until the transaction ends. For
- example, if a table <literal>t1</literal> is in use by a
- transaction, another session that attempts to execute
- <literal role="stmt" condition="drop-table">DROP TABLE
- t1</literal> will block until the transaction ends.
- </para>
-
- <para>
- If the server acquires metadata locks for a statement that is
- syntactically valid but fails during execution, it does not
- release the locks early. Lock release is still deferred to the
- end of the transaction because the failed statement is written
- to the binary log and the locks protect log consistency.
- </para>
-
- <para>
- Metadata locks acquired during a
- <literal role="stmt">PREPARE</literal> statement are released
- once the statement has been prepared, even if preparation occurs
- within a multiple-statement transaction.
- </para>
-
- <para>
- Before MySQL 5.5.3, when a transaction acquired a metadata lock
- for a table used within a statement, it released the lock at the
- end of the statement. This approach had the disadvantage that if
- a DDL statement occurred for a table that was being used by
- another session in an active transaction, statements could be
- written to the binary log in the wrong order.
- </para>
-
- </section>
-
- <section id="external-locking">
-
- <title>External Locking</title>
-
- <indexterm>
- <primary>external locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>external</secondary>
- </indexterm>
-
- <para>
- External locking is the use of file system locking to manage
- contention for database tables by multiple processes. External
- locking is used in situations where a single process such as the
- MySQL server cannot be assumed to be the only process that
- requires access to tables. Here are some examples:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- If you run multiple servers that use the same database
- directory (not recommended), each server must have external
- locking enabled.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you use <command>myisamchk</command> to perform table
- maintenance operations on <literal>MyISAM</literal> tables,
- you must either ensure that the server is not running, or
- that the server has external locking enabled so that it
- locks table files as necessary to coordinate with
- <command>myisamchk</command> for access to the tables. The
- same is true for use of <command>myisampack</command> to
- pack <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- If the server is run with external locking enabled, you can
- use <command>myisamchk</command> at any time for read
- operations such a checking tables. In this case, if the
- server tries to update a table that
- <command>myisamchk</command> is using, the server will wait
- for <command>myisamchk</command> to finish before it
- continues.
- </para>
-
- <para>
- If you use <command>myisamchk</command> for write operations
- such as repairing or optimizing tables, or if you use
- <command>myisampack</command> to pack tables, you
- <emphasis>must</emphasis> always ensure that the
- <command>mysqld</command> server is not using the table. If
- you don't stop <command>mysqld</command>, you should at
- least do a <command>mysqladmin flush-tables</command> before
- you run <command>myisamchk</command>. Your tables
- <emphasis>may become corrupted</emphasis> if the server and
- <command>myisamchk</command> access the tables
- simultaneously.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With external locking in effect, each process that requires
- access to a table acquires a file system lock for the table
- files before proceeding to access the table. If all necessary
- locks cannot be acquired, the process is blocked from accessing
- the table until the locks can be obtained (after the process
- that currently holds the locks releases them).
- </para>
-
- <para>
- External locking affects server performance because the server
- must sometimes wait for other processes before it can access
- tables.
- </para>
-
- <para>
- External locking is unnecessary if you run a single server to
- access a given data directory (which is the usual case) and if
- no other programs such as <command>myisamchk</command> need to
- modify tables while the server is running. If you only
- <emphasis>read</emphasis> tables with other programs, external
- locking is not required, although <command>myisamchk</command>
- might report warnings if the server changes tables while
- <command>myisamchk</command> is reading them.
- </para>
-
- <para>
- With external locking disabled, to use
- <command>myisamchk</command>, you must either stop the server
- while <command>myisamchk</command> executes or else lock and
- flush the tables before running <command>myisamchk</command>.
- (See <xref linkend="system-optimization"/>.) To avoid this
- requirement, use the <literal role="stmt">CHECK TABLE</literal>
- and <literal role="stmt">REPAIR TABLE</literal> statements to
- check and repair <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- For <command>mysqld</command>, external locking is controlled by
- the value of the
- <literal role="sysvar">skip_external_locking</literal> system
- variable. When this variable is enabled, external locking is
- disabled, and vice versa. From MySQL 4.0 on, external locking is
- disabled by default. Before MySQL 4.0, external locking is
- enabled by default on Linux or when MySQL is configured to use
- MIT-pthreads.
- </para>
-
- <para>
- Use of external locking can be controlled at server startup by
- using the <option role="mysqld">--external-locking</option> or
- <option role="mysqld">--skip-external-locking</option> option.
- </para>
-
- <para>
- If you do use external locking option to enable updates to
- <literal>MyISAM</literal> tables from many MySQL processes, you
- must ensure that the following conditions are satisfied:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- You should not use the query cache for queries that use
- tables that are updated by another process.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You should not start the server with the
- <option role="mysqld">--delay-key-write=ALL</option> option
- or use the <literal>DELAY_KEY_WRITE=1</literal> table option
- for any shared tables. Otherwise, index corruption can
- occur.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The easiest way to satisfy these conditions is to always use
- <option role="mysqld">--external-locking</option> together with
- <option role="mysqld">--delay-key-write=OFF</option> and
- <option role="sysvar">--query-cache-size=0</option>. (This is
- not done by default because in many setups it is useful to have
- a mixture of the preceding options.)
- </para>
-
- </section>
-
- </section>
-
- <section id="optimizing-database-structure">
-
- <title>Optimizing Database Structure</title>
-
- <section id="data-size">
-
- <title>Make Your Data as Small as Possible</title>
-
- <indexterm>
- <primary>data</primary>
- <secondary>size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>reducing</primary>
- <secondary>data size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>storage space</primary>
- <secondary>minimizing</secondary>
- </indexterm>
-
- <indexterm>
- <primary>tables</primary>
- <secondary>improving performance</secondary>
- </indexterm>
-
- <indexterm>
- <primary>performance</primary>
- <secondary>improving</secondary>
- </indexterm>
-
- <para>
- One of the most basic optimizations is to design your tables to
- take as little space on the disk as possible. This can result in
- huge improvements because disk reads are faster, and smaller
- tables normally require less main memory while their contents
- are being actively processed during query execution. Indexing
- also is a lesser resource burden if done on smaller columns.
- </para>
-
- <para>
- MySQL supports many different storage engines (table types) and
- row formats. For each table, you can decide which storage and
- indexing method to use. Choosing the proper table format for
- your application may give you a big performance gain. See
- <xref linkend="storage-engines"/>.
- </para>
-
- <para>
- You can get better performance for a table and minimize storage
- space by using the techniques listed here:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Use the most efficient (smallest) data types possible. MySQL
- has many specialized types that save disk space and memory.
- For example, use the smaller integer types if possible to
- get smaller tables. <literal role="type">MEDIUMINT</literal>
- is often a better choice than
- <literal role="type">INT</literal> because a
- <literal role="type">MEDIUMINT</literal> column uses 25%
- less space.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Declare columns to be <literal>NOT NULL</literal> if
- possible. It makes everything faster and you save one bit
- per column. If you really need <literal>NULL</literal> in
- your application, you should definitely use it. Just avoid
- having it on all columns by default.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For <literal>MyISAM</literal> tables, if you do not have any
- variable-length columns
- (<literal role="type">VARCHAR</literal>,
- <literal role="type">TEXT</literal>, or
- <literal role="type">BLOB</literal> columns), a fixed-size
- row format is used. This is faster but unfortunately may
- waste some space. See
- <xref linkend="myisam-table-formats"/>. You can hint that
- you want to have fixed length rows even if you have
- <literal role="type">VARCHAR</literal> columns with the
- <literal role="stmt">CREATE TABLE</literal> option
- <literal>ROW_FORMAT=FIXED</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>InnoDB</literal> tables use a compact storage
- format. In versions of MySQL earlier than 5.0.3,
- <literal>InnoDB</literal> rows contain some redundant
- information, such as the number of columns and the length of
- each column, even for fixed-size columns. By default, tables
- are created in the compact format
- (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
- downgrade to older versions of MySQL, you can request the
- old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
- </para>
-
- <para>
- The presence of the compact row format decreases row storage
- space by about 20% at the cost of increasing CPU use for
- some operations. If your workload is a typical one that is
- limited by cache hit rates and disk speed it is likely to be
- faster. If it is a rare case that is limited by CPU speed,
- it might be slower.
- </para>
-
- <para>
- The compact <literal>InnoDB</literal> format also changes
- how <literal role="type">CHAR</literal> columns containing
- UTF-8 data are stored. With
- <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
- <literal>CHAR(<replaceable>N</replaceable>)</literal>
- occupies 3 × <replaceable>N</replaceable> bytes, given
- that the maximum length of a UTF-8 encoded character is
- three bytes. Many languages can be written primarily using
- single-byte UTF-8 characters, so a fixed storage length
- often wastes space. With
- <literal>ROW_FORMAT=COMPACT</literal> format,
- <literal>InnoDB</literal> allocates a variable amount of
- storage in the range from <replaceable>N</replaceable> to 3
- × <replaceable>N</replaceable> bytes for these columns
- by stripping trailing spaces if necessary. The minimum
- storage length is kept as <replaceable>N</replaceable> bytes
- to facilitate in-place updates in typical cases.
- </para>
- </listitem>
-
- <listitem>
- <para>
- The primary index of a table should be as short as possible.
- This makes identification of each row easy and efficient.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Create only the indexes that you really need. Indexes are
- good for retrieval but bad when you need to store data
- quickly. If you access a table mostly by searching on a
- combination of columns, create an index on them. The first
- part of the index should be the column most used. If you
- <emphasis>always</emphasis> use many columns when selecting
- from the table, the first column in the index should be the
- one with the most duplicates to obtain better compression of
- the index.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If it is very likely that a string column has a unique
- prefix on the first number of characters, it is better to
- index only this prefix, using MySQL's support for creating
- an index on the leftmost part of the column (see
- <xref linkend="create-index"/>). Shorter indexes are faster,
- not only because they require less disk space, but because
- they also give you more hits in the index cache, and thus
- fewer disk seeks. See <xref linkend="server-parameters"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- In some circumstances, it can be beneficial to split into
- two a table that is scanned very often. This is especially
- true if it is a dynamic-format table and it is possible to
- use a smaller static format table that can be used to find
- the relevant rows when scanning the table.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="indexes">
-
<title>Column Indexes</title>
<indexterm>
@@ -10079,7 +8895,7 @@
MySQL can create composite indexes (that is, indexes on multiple
columns). An index may consist of up to 16 columns. For certain
data types, you can index a prefix of the column (see
- <xref linkend="indexes"/>).
+ <xref linkend="column-indexes"/>).
</para>
<para>
@@ -11775,6 +10591,1196 @@
</section>
+ </section>
+
+ <section id="locking-issues">
+
+ <title>Locking Issues</title>
+
+ <para>
+ MySQL manages contention for table contents using locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Internal locking is performed within the MySQL server itself
+ to manage contention for table contents by multiple threads.
+ This type of locking is internal because it is performed
+ entirely by the server and involves no other programs. See
+ <xref linkend="internal-locking"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ External locking occurs when the server and other programs
+ lock table files to coordinate among themselves which program
+ can access the tables at which time. See
+ <xref linkend="external-locking"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <section id="internal-locking">
+
+ <title>Internal Locking Methods</title>
+
+ <indexterm>
+ <primary>internal locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>internal</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking methods</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>methods</primary>
+ <secondary>locking</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>table-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>row-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>table-level</secondary>
+ </indexterm>
+
+ <para>
+ This section discusses internal locking; that is, locking
+ performed within the MySQL server itself to manage contention
+ for table contents by multiple sessions. This type of locking is
+ internal because it is performed entirely by the server and
+ involves no other programs. External locking occurs when the
+ server and other programs lock table files to coordinate among
+ themselves which program can access the tables at which time.
+ See <xref linkend="external-locking"/>.
+ </para>
+
+ <para>
+ MySQL uses table-level locking for <literal>MyISAM</literal>,
+ <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
+ and row-level locking for <literal>InnoDB</literal> tables.
+ </para>
+
+ <para>
+ In many cases, you can make an educated guess about which
+ locking type is best for an application, but generally it is
+ difficult to say that a given lock type is better than another.
+ Everything depends on the application and different parts of an
+ application may require different lock types.
+ </para>
+
+ <para>
+ To decide whether you want to use a storage engine with
+ row-level locking, you should look at what your application does
+ and what mix of select and update statements it uses. For
+ example, most Web applications perform many selects, relatively
+ few deletes, updates based mainly on key values, and inserts
+ into a few specific tables. The base MySQL
+ <literal>MyISAM</literal> setup is very well tuned for this.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ The MySQL Enterprise Monitor provides expert advice on when to
+ use table-level locking and when to use row-level locking. To
+ subscribe, see &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+
+ <para>
+ Table locking in MySQL is deadlock-free for storage engines that
+ use table-level locking. Deadlock avoidance is managed by always
+ requesting all needed locks at once at the beginning of a query
+ and always locking the tables in the same order.
+ </para>
+
+ <para>
+ MySQL grants table write locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no locks on the table, put a write lock on it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the write lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ MySQL grants table read locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no write locks on the table, put a read lock on
+ it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the read lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ Table updates are given higher priority than table retrievals.
+ Therefore, when a lock is released, the lock is made available
+ to the requests in the write lock queue and then to the requests
+ in the read lock queue. This ensures that updates to a table are
+ not <quote>starved</quote> even if there is heavy
+ <literal role="stmt">SELECT</literal> activity for the table.
+ However, if you have many updates for a table,
+ <literal role="stmt">SELECT</literal> statements wait until
+ there are no more updates.
+ </para>
+
+ <para>
+ For information on altering the priority of reads and writes,
+ see <xref linkend="table-locking"/>.
+ </para>
+
+ <para>
+ You can analyze the table lock contention on your system by
+ checking the
+ <literal role="statvar">Table_locks_immediate</literal> and
+ <literal role="statvar">Table_locks_waited</literal> status
+ variables, which indicate the number of times that requests for
+ table locks could be granted immediately and the number that had
+ to wait, respectively:
+ </para>
+
+<programlisting>
+mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
++-----------------------+---------+
+| Variable_name | Value |
++-----------------------+---------+
+| Table_locks_immediate | 1151552 |
+| Table_locks_waited | 15324 |
++-----------------------+---------+
+</programlisting>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no free
+ blocks in the middle of the data file, rows are always inserted
+ at the end of the data file. In this case, you can freely mix
+ concurrent <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> statements for a
+ <literal>MyISAM</literal> table without locks. That is, you can
+ insert rows into a <literal>MyISAM</literal> table at the same
+ time other clients are reading from it. Holes can result from
+ rows having been deleted from or updated in the middle of the
+ table. If there are holes, concurrent inserts are disabled but
+ are enabled again automatically when all holes have been filled
+ with new data.. This behavior is altered by the
+ <literal role="sysvar">concurrent_insert</literal> system
+ variable. See <xref linkend="concurrent-inserts"/>.
+ </para>
+
+ <para>
+ If you acquire a table lock explicitly with
+ <literal role="stmt">LOCK TABLES</literal>, you can request a
+ <literal>READ LOCAL</literal> lock rather than a
+ <literal>READ</literal> lock to enable other sessions to perform
+ concurrent inserts while you have the table locked.
+ </para>
+
+ <para>
+ To perform many <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> operations on a table
+ <literal>real_table</literal> when concurrent inserts are not
+ possible, you can insert rows into a temporary table
+ <literal>temp_table</literal> and update the real table with the
+ rows from the temporary table periodically. This can be done
+ with the following code:
+ </para>
+
+<programlisting>
+mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
+mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
+mysql> <userinput>DELETE FROM temp_table;</userinput>
+mysql> <userinput>UNLOCK TABLES;</userinput>
+</programlisting>
+
+ <para>
+ <literal>InnoDB</literal> uses row locks. Deadlocks are possible
+ for <literal>InnoDB</literal> because it automatically acquires
+ locks during the processing of SQL statements, not at the start
+ of the transaction.
+ </para>
+
+ <para>
+ Advantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Fewer lock conflicts when different sessions access
+ different rows
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fewer changes for rollbacks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Possible to lock a single row for a long time
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Disadvantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Requires more memory than table-level locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than table-level locks when used on a large part of
+ the table because you must acquire many more locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than other locks if you often do <literal>GROUP
+ BY</literal> operations on a large part of the data or if
+ you must scan the entire table frequently
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Generally, table locks are superior to row-level locks in the
+ following cases:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Most statements for the table are reads
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Statements for the table are a mix of reads and writes,
+ where writes are updates or deletes for a single row that
+ can be fetched with one key read:
+ </para>
+
+<programlisting>
+UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal role="stmt">SELECT</literal> combined with
+ concurrent <literal role="stmt">INSERT</literal> statements,
+ and very few <literal role="stmt">UPDATE</literal> or
+ <literal role="stmt">DELETE</literal> statements
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Many scans or <literal>GROUP BY</literal> operations on the
+ entire table without any writers
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With higher-level locks, you can more easily tune applications
+ by supporting locks of different types, because the lock
+ overhead is less than for row-level locks.
+ </para>
+
+ <para>
+ Options other than row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Versioning (such as that used in MySQL for concurrent
+ inserts) where it is possible to have one writer at the same
+ time as many readers. This means that the database or table
+ supports different views for the data depending on when
+ access begins. Other common terms for this are <quote>time
+ travel,</quote> <quote>copy on write,</quote> or <quote>copy
+ on demand.</quote>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Copy on demand is in many cases superior to row-level
+ locking. However, in the worst case, it can use much more
+ memory than using normal locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Instead of using row-level locks, you can employ
+ application-level locks, such as those provided by
+ <literal role="func">GET_LOCK()</literal> and
+ <literal role="func">RELEASE_LOCK()</literal> in MySQL.
+ These are advisory locks, so they work only with
+ applications that cooperate with each other. See
+ <xref linkend="miscellaneous-functions"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="table-locking">
+
+ <title>Table Locking Issues</title>
+
+ <indexterm>
+ <primary>problems</primary>
+ <secondary>table locking</secondary>
+ </indexterm>
+
+ <para>
+ To achieve a very high lock speed, MySQL uses table locking
+ (instead of page, row, or column locking) for all storage
+ engines except <literal>InnoDB</literal>.
+ </para>
+
+ <para>
+ For <literal>InnoDB</literal> tables, MySQL uses table locking
+ only if you explicitly lock the table with
+ <literal role="stmt">LOCK TABLES</literal>. For this storage
+ engine, avoid using <literal role="stmt">LOCK TABLES</literal>
+ at all, because <literal>InnoDB</literal> uses automatic
+ row-level locking to ensure transaction isolation.
+ </para>
+
+ <para>
+ For large tables, table locking is often better than row
+ locking, but there are some disadvantages:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Table locking enables many sessions to read from a table at
+ the same time, but if a session wants to write to a table,
+ it must first get exclusive access. During the update, all
+ other sessions that want to access this particular table
+ must wait until the update is done.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Table locking causes problems in cases such as when a
+ session is waiting because the disk is full and free space
+ needs to become available before the session can proceed. In
+ this case, all sessions that want to access the problem
+ table are also put in a waiting state until more disk space
+ is made available.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Table locking is also disadvantageous under the following
+ scenario:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ A session issues a <literal role="stmt">SELECT</literal>
+ that takes a long time to run.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session then issues an
+ <literal role="stmt">UPDATE</literal> on the same table.
+ This session waits until the
+ <literal role="stmt">SELECT</literal> is finished.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session issues another
+ <literal role="stmt">SELECT</literal> statement on the same
+ table. Because <literal role="stmt">UPDATE</literal> has
+ higher priority than <literal role="stmt">SELECT</literal>,
+ this <literal role="stmt">SELECT</literal> waits for the
+ <literal role="stmt">UPDATE</literal> to finish,
+ <emphasis>after</emphasis> waiting for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following items describe some ways to avoid or reduce
+ contention caused by table locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Try to get the <literal role="stmt">SELECT</literal>
+ statements to run faster so that they lock tables for a
+ shorter time. You might have to create some summary tables
+ to do this.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with
+ <option role="mysqld">--low-priority-updates</option>. For
+ storage engines that use only table-level locking (such as
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
+ <literal>MERGE</literal>), this gives all statements that
+ update (modify) a table lower priority than
+ <literal role="stmt">SELECT</literal> statements. In this
+ case, the second <literal role="stmt">SELECT</literal>
+ statement in the preceding scenario would execute before the
+ <literal role="stmt">UPDATE</literal> statement, and would
+ not need to wait for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To specify that all updates issued in a specific connection
+ should be done with low priority, set the
+ <literal role="sysvar">low_priority_updates</literal> server
+ system variable equal to 1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">INSERT</literal>,
+ <literal role="stmt">UPDATE</literal>, or
+ <literal role="stmt">DELETE</literal> statement lower
+ priority, use the <literal>LOW_PRIORITY</literal> attribute.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">SELECT</literal>
+ statement higher priority, use the
+ <literal>HIGH_PRIORITY</literal> attribute. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with a low value for the
+ <literal role="sysvar">max_write_lock_count</literal> system
+ variable to force MySQL to temporarily elevate the priority
+ of all <literal role="stmt">SELECT</literal> statements that
+ are waiting for a table after a specific number of inserts
+ to the table occur. This permits <literal>READ</literal>
+ locks after a certain number of <literal>WRITE</literal>
+ locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with
+ <literal role="stmt">INSERT</literal> combined with
+ <literal role="stmt">SELECT</literal>, consider switching to
+ <literal>MyISAM</literal> tables, which support concurrent
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">INSERT</literal> statements. (See
+ <xref linkend="concurrent-inserts"/>.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you mix inserts and deletes on the same table,
+ <literal role="stmt">INSERT DELAYED</literal> may be of
+ great help. See <xref linkend="insert-delayed"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with mixed
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">DELETE</literal> statements, the
+ <literal>LIMIT</literal> option to
+ <literal role="stmt">DELETE</literal> may help. See
+ <xref linkend="delete"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Using <literal>SQL_BUFFER_RESULT</literal> with
+ <literal role="stmt">SELECT</literal> statements can help to
+ make the duration of table locks shorter. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You could change the locking code in
+ <filename>mysys/thr_lock.c</filename> to use a single queue.
+ In this case, write locks and read locks would have the same
+ priority, which might help some applications.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Here are some tips concerning table locks in MySQL:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Concurrent users are not a problem if you do not mix updates
+ with selects that need to examine many rows in the same
+ table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can use <literal role="stmt">LOCK TABLES</literal> to
+ increase speed, because many updates within a single lock is
+ much faster than updating without locks. Splitting table
+ contents into separate tables may also help.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you encounter speed problems with table locks in MySQL,
+ you may be able to improve performance by converting some of
+ your tables to <literal>InnoDB</literal>. See
+ <xref linkend="innodb"/>.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ Lock contention can seriously degrade performance. The
+ MySQL Enterprise Monitor provides expert advice on
+ avoiding this problem. To subscribe, see
+ &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="concurrent-inserts">
+
+ <title>Concurrent Inserts</title>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no holes
+ in the data file (deleted rows in the middle), an
+ <literal role="stmt">INSERT</literal> statement can be executed
+ to add rows to the end of the table at the same time that
+ <literal role="stmt">SELECT</literal> statements are reading
+ rows from the table. If there are multiple
+ <literal role="stmt">INSERT</literal> statements, they are
+ queued and performed in sequence, concurrently with the
+ <literal role="stmt">SELECT</literal> statements. The results of
+ a concurrent <literal role="stmt">INSERT</literal> may not be
+ visible immediately.
+ </para>
+
+ <para>
+ The <literal role="sysvar">concurrent_insert</literal> system
+ variable can be set to modify the concurrent-insert processing.
+ By default, the variable is set to <literal>AUTO</literal> (or
+ 1) and concurrent inserts are handled as just described. If
+ <literal role="sysvar">concurrent_insert</literal> is set to
+ <literal>NEVER</literal> (or 0), concurrent inserts are
+ disabled. If the variable is set to <literal>ALWAYS</literal>
+ (or 2), concurrent inserts at the end of the table are allowed
+ even for tables that have deleted rows. See also the description
+ of the
+ <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
+ system variable.
+ </para>
+
+ <para>
+ Under circumstances where concurrent inserts can be used, there
+ is seldom any need to use the <literal>DELAYED</literal>
+ modifier for <literal role="stmt">INSERT</literal> statements.
+ See <xref linkend="insert-delayed"/>.
+ </para>
+
+ <para>
+ If you are using the binary log, concurrent inserts are
+ converted to normal inserts for <literal>CREATE ...
+ SELECT</literal> or
+ <literal role="stmt" condition="insert-select">INSERT ...
+ SELECT</literal> statements. This is done to ensure that you can
+ re-create an exact copy of your tables by applying the log
+ during a backup operation. See <xref linkend="binary-log"/>. In
+ addition, for those statements a read lock is placed on the
+ selected-from table such that inserts into that table are
+ blocked. The effect is that concurrent inserts for that table
+ must wait as well.
+ </para>
+
+ <para>
+ With <literal role="stmt" condition="load-data">LOAD DATA
+ INFILE</literal>, if you specify <literal>CONCURRENT</literal>
+ with a <literal>MyISAM</literal> table that satisfies the
+ condition for concurrent inserts (that is, it contains no free
+ blocks in the middle), other sessions can retrieve data from the
+ table while <literal role="stmt">LOAD DATA</literal> is
+ executing. Use of the <literal>CONCURRENT</literal> option
+ affects the performance of <literal role="stmt">LOAD
+ DATA</literal> a bit, even if no other session is using the
+ table at the same time.
+ </para>
+
+ <para>
+ If you specify <literal>HIGH_PRIORITY</literal>, it overrides
+ the effect of the
+ <option role="mysqld">--low-priority-updates</option> option if
+ the server was started with that option. It also causes
+ concurrent inserts not to be used.
+ </para>
+
+ <para>
+ For <literal role="stmt" condition="lock-tables">LOCK
+ TABLE</literal>, the difference between <literal>READ
+ LOCAL</literal> and <literal>READ</literal> is that
+ <literal>READ LOCAL</literal> permits nonconflicting
+ <literal role="stmt">INSERT</literal> statements (concurrent
+ inserts) to execute while the lock is held. However, this cannot
+ be used if you are going to manipulate the database using
+ processes external to the server while you hold the lock.
+ </para>
+
+ </section>
+
+ <section id="metadata-locking">
+
+ <title>Metadata Locking Within Transactions</title>
+
+ <indexterm>
+ <primary>metadata locking</primary>
+ <secondary>transactions</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>transactions</primary>
+ <secondary>metadata locking</secondary>
+ </indexterm>
+
+ <para>
+ To ensure transaction serializability, the server must not allow
+ one session to perform a data definition language (DDL)
+ statement on a table that is used in an uncompleted transaction
+ in another session.
+ </para>
+
+ <para>
+ As of MySQL 5.5.3, the server achieves this by acquiring
+ metadata locks on tables used within a transaction and deferring
+ release of those locks until the transaction ends. A metadata
+ lock on a table prevents changes to the table's structure. This
+ locking approach has the implication that a table that is being
+ used by a transaction within one session cannot be used in DDL
+ statements by other sessions until the transaction ends. For
+ example, if a table <literal>t1</literal> is in use by a
+ transaction, another session that attempts to execute
+ <literal role="stmt" condition="drop-table">DROP TABLE
+ t1</literal> will block until the transaction ends.
+ </para>
+
+ <para>
+ If the server acquires metadata locks for a statement that is
+ syntactically valid but fails during execution, it does not
+ release the locks early. Lock release is still deferred to the
+ end of the transaction because the failed statement is written
+ to the binary log and the locks protect log consistency.
+ </para>
+
+ <para>
+ Metadata locks acquired during a
+ <literal role="stmt">PREPARE</literal> statement are released
+ once the statement has been prepared, even if preparation occurs
+ within a multiple-statement transaction.
+ </para>
+
+ <para>
+ Before MySQL 5.5.3, when a transaction acquired a metadata lock
+ for a table used within a statement, it released the lock at the
+ end of the statement. This approach had the disadvantage that if
+ a DDL statement occurred for a table that was being used by
+ another session in an active transaction, statements could be
+ written to the binary log in the wrong order.
+ </para>
+
+ </section>
+
+ <section id="external-locking">
+
+ <title>External Locking</title>
+
+ <indexterm>
+ <primary>external locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>external</secondary>
+ </indexterm>
+
+ <para>
+ External locking is the use of file system locking to manage
+ contention for database tables by multiple processes. External
+ locking is used in situations where a single process such as the
+ MySQL server cannot be assumed to be the only process that
+ requires access to tables. Here are some examples:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ If you run multiple servers that use the same database
+ directory (not recommended), each server must have external
+ locking enabled.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you use <command>myisamchk</command> to perform table
+ maintenance operations on <literal>MyISAM</literal> tables,
+ you must either ensure that the server is not running, or
+ that the server has external locking enabled so that it
+ locks table files as necessary to coordinate with
+ <command>myisamchk</command> for access to the tables. The
+ same is true for use of <command>myisampack</command> to
+ pack <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ If the server is run with external locking enabled, you can
+ use <command>myisamchk</command> at any time for read
+ operations such a checking tables. In this case, if the
+ server tries to update a table that
+ <command>myisamchk</command> is using, the server will wait
+ for <command>myisamchk</command> to finish before it
+ continues.
+ </para>
+
+ <para>
+ If you use <command>myisamchk</command> for write operations
+ such as repairing or optimizing tables, or if you use
+ <command>myisampack</command> to pack tables, you
+ <emphasis>must</emphasis> always ensure that the
+ <command>mysqld</command> server is not using the table. If
+ you don't stop <command>mysqld</command>, you should at
+ least do a <command>mysqladmin flush-tables</command> before
+ you run <command>myisamchk</command>. Your tables
+ <emphasis>may become corrupted</emphasis> if the server and
+ <command>myisamchk</command> access the tables
+ simultaneously.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With external locking in effect, each process that requires
+ access to a table acquires a file system lock for the table
+ files before proceeding to access the table. If all necessary
+ locks cannot be acquired, the process is blocked from accessing
+ the table until the locks can be obtained (after the process
+ that currently holds the locks releases them).
+ </para>
+
+ <para>
+ External locking affects server performance because the server
+ must sometimes wait for other processes before it can access
+ tables.
+ </para>
+
+ <para>
+ External locking is unnecessary if you run a single server to
+ access a given data directory (which is the usual case) and if
+ no other programs such as <command>myisamchk</command> need to
+ modify tables while the server is running. If you only
+ <emphasis>read</emphasis> tables with other programs, external
+ locking is not required, although <command>myisamchk</command>
+ might report warnings if the server changes tables while
+ <command>myisamchk</command> is reading them.
+ </para>
+
+ <para>
+ With external locking disabled, to use
+ <command>myisamchk</command>, you must either stop the server
+ while <command>myisamchk</command> executes or else lock and
+ flush the tables before running <command>myisamchk</command>.
+ (See <xref linkend="system-optimization"/>.) To avoid this
+ requirement, use the <literal role="stmt">CHECK TABLE</literal>
+ and <literal role="stmt">REPAIR TABLE</literal> statements to
+ check and repair <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ For <command>mysqld</command>, external locking is controlled by
+ the value of the
+ <literal role="sysvar">skip_external_locking</literal> system
+ variable. When this variable is enabled, external locking is
+ disabled, and vice versa. From MySQL 4.0 on, external locking is
+ disabled by default. Before MySQL 4.0, external locking is
+ enabled by default on Linux or when MySQL is configured to use
+ MIT-pthreads.
+ </para>
+
+ <para>
+ Use of external locking can be controlled at server startup by
+ using the <option role="mysqld">--external-locking</option> or
+ <option role="mysqld">--skip-external-locking</option> option.
+ </para>
+
+ <para>
+ If you do use external locking option to enable updates to
+ <literal>MyISAM</literal> tables from many MySQL processes, you
+ must ensure that the following conditions are satisfied:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ You should not use the query cache for queries that use
+ tables that are updated by another process.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You should not start the server with the
+ <option role="mysqld">--delay-key-write=ALL</option> option
+ or use the <literal>DELAY_KEY_WRITE=1</literal> table option
+ for any shared tables. Otherwise, index corruption can
+ occur.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The easiest way to satisfy these conditions is to always use
+ <option role="mysqld">--external-locking</option> together with
+ <option role="mysqld">--delay-key-write=OFF</option> and
+ <option role="sysvar">--query-cache-size=0</option>. (This is
+ not done by default because in many setups it is useful to have
+ a mixture of the preceding options.)
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="optimizing-database-structure">
+
+ <title>Optimizing Database Structure</title>
+
+ <section id="data-size">
+
+ <title>Make Your Data as Small as Possible</title>
+
+ <indexterm>
+ <primary>data</primary>
+ <secondary>size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>reducing</primary>
+ <secondary>data size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>storage space</primary>
+ <secondary>minimizing</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>tables</primary>
+ <secondary>improving performance</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>performance</primary>
+ <secondary>improving</secondary>
+ </indexterm>
+
+ <para>
+ One of the most basic optimizations is to design your tables to
+ take as little space on the disk as possible. This can result in
+ huge improvements because disk reads are faster, and smaller
+ tables normally require less main memory while their contents
+ are being actively processed during query execution. Indexing
+ also is a lesser resource burden if done on smaller columns.
+ </para>
+
+ <para>
+ MySQL supports many different storage engines (table types) and
+ row formats. For each table, you can decide which storage and
+ indexing method to use. Choosing the proper table format for
+ your application may give you a big performance gain. See
+ <xref linkend="storage-engines"/>.
+ </para>
+
+ <para>
+ You can get better performance for a table and minimize storage
+ space by using the techniques listed here:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Use the most efficient (smallest) data types possible. MySQL
+ has many specialized types that save disk space and memory.
+ For example, use the smaller integer types if possible to
+ get smaller tables. <literal role="type">MEDIUMINT</literal>
+ is often a better choice than
+ <literal role="type">INT</literal> because a
+ <literal role="type">MEDIUMINT</literal> column uses 25%
+ less space.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Declare columns to be <literal>NOT NULL</literal> if
+ possible. It makes everything faster and you save one bit
+ per column. If you really need <literal>NULL</literal> in
+ your application, you should definitely use it. Just avoid
+ having it on all columns by default.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For <literal>MyISAM</literal> tables, if you do not have any
+ variable-length columns
+ (<literal role="type">VARCHAR</literal>,
+ <literal role="type">TEXT</literal>, or
+ <literal role="type">BLOB</literal> columns), a fixed-size
+ row format is used. This is faster but unfortunately may
+ waste some space. See
+ <xref linkend="myisam-table-formats"/>. You can hint that
+ you want to have fixed length rows even if you have
+ <literal role="type">VARCHAR</literal> columns with the
+ <literal role="stmt">CREATE TABLE</literal> option
+ <literal>ROW_FORMAT=FIXED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>InnoDB</literal> tables use a compact storage
+ format. In versions of MySQL earlier than 5.0.3,
+ <literal>InnoDB</literal> rows contain some redundant
+ information, such as the number of columns and the length of
+ each column, even for fixed-size columns. By default, tables
+ are created in the compact format
+ (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
+ downgrade to older versions of MySQL, you can request the
+ old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
+ </para>
+
+ <para>
+ The presence of the compact row format decreases row storage
+ space by about 20% at the cost of increasing CPU use for
+ some operations. If your workload is a typical one that is
+ limited by cache hit rates and disk speed it is likely to be
+ faster. If it is a rare case that is limited by CPU speed,
+ it might be slower.
+ </para>
+
+ <para>
+ The compact <literal>InnoDB</literal> format also changes
+ how <literal role="type">CHAR</literal> columns containing
+ UTF-8 data are stored. With
+ <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
+ <literal>CHAR(<replaceable>N</replaceable>)</literal>
+ occupies 3 × <replaceable>N</replaceable> bytes, given
+ that the maximum length of a UTF-8 encoded character is
+ three bytes. Many languages can be written primarily using
+ single-byte UTF-8 characters, so a fixed storage length
+ often wastes space. With
+ <literal>ROW_FORMAT=COMPACT</literal> format,
+ <literal>InnoDB</literal> allocates a variable amount of
+ storage in the range from <replaceable>N</replaceable> to 3
+ × <replaceable>N</replaceable> bytes for these columns
+ by stripping trailing spaces if necessary. The minimum
+ storage length is kept as <replaceable>N</replaceable> bytes
+ to facilitate in-place updates in typical cases.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The primary index of a table should be as short as possible.
+ This makes identification of each row easy and efficient.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create only the indexes that you really need. Indexes are
+ good for retrieval but bad when you need to store data
+ quickly. If you access a table mostly by searching on a
+ combination of columns, create an index on them. The first
+ part of the index should be the column most used. If you
+ <emphasis>always</emphasis> use many columns when selecting
+ from the table, the first column in the index should be the
+ one with the most duplicates to obtain better compression of
+ the index.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If it is very likely that a string column has a unique
+ prefix on the first number of characters, it is better to
+ index only this prefix, using MySQL's support for creating
+ an index on the leftmost part of the column (see
+ <xref linkend="create-index"/>). Shorter indexes are faster,
+ not only because they require less disk space, but because
+ they also give you more hits in the index cache, and thus
+ fewer disk seeks. See <xref linkend="server-parameters"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ In some circumstances, it can be beneficial to split into
+ two a table that is scanned very often. This is especially
+ true if it is a dynamic-format table and it is possible to
+ use a smaller static format table that can be used to find
+ the relevant rows when scanning the table.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
<section id="table-cache">
<title>How MySQL Opens and Closes Tables</title>
Modified: trunk/refman-5.5/renamed-nodes.txt
===================================================================
--- trunk/refman-5.5/renamed-nodes.txt 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.5/renamed-nodes.txt 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 0; 624 bytes
@@ -26,6 +26,7 @@
change-column-order alter-table 2011-04-09
charset-collate-tricky charset-collation-expressions 2011-06-14
index-condition-pushdown-optimization condition-pushdown-optimization 2011-06-23
+indexes column-indexes 2011-07-14
load-data-from-master introduction 2011-03-06
load-table-from-master introduction 2011-03-06
mysql-copyright index 2011-04-09
Modified: trunk/refman-5.5/sql-syntax-data-definition.xml
===================================================================
--- trunk/refman-5.5/sql-syntax-data-definition.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-5.5/sql-syntax-data-definition.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 663 bytes
@@ -4790,7 +4790,7 @@
<literal role="type">VARBINARY</literal>, and
<literal role="type">BLOB</literal> columns. Indexing only a
prefix of column values like this can make the index file much
- smaller. See <xref linkend="indexes"/>.
+ smaller. See <xref linkend="column-indexes"/>.
</para>
<indexterm>
Modified: trunk/refman-6.0/data-types.xml
===================================================================
--- trunk/refman-6.0/data-types.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-6.0/data-types.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 594 bytes
@@ -4644,7 +4644,7 @@
specify an index prefix length. For
<literal role="type">CHAR</literal> and
<literal role="type">VARCHAR</literal>, a prefix length is
- optional. See <xref linkend="indexes"/>.
+ optional. See <xref linkend="column-indexes"/>.
</para>
</listitem>
Modified: trunk/refman-6.0/optimization.xml
===================================================================
--- trunk/refman-6.0/optimization.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-6.0/optimization.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 3, Lines Added: 1194, Lines Deleted: 1188; 88254 bytes
@@ -9929,1196 +9929,12 @@
</section>
- <section id="locking-issues">
+ <section id="optimization-indexes">
- <title>Locking Issues</title>
+ <title>Optimization and Indexes</title>
- <para>
- MySQL manages contention for table contents using locking:
- </para>
+ <section id="column-indexes">
- <itemizedlist>
-
- <listitem>
- <para>
- Internal locking is performed within the MySQL server itself
- to manage contention for table contents by multiple threads.
- This type of locking is internal because it is performed
- entirely by the server and involves no other programs. See
- <xref linkend="internal-locking"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- External locking occurs when the server and other programs
- lock table files to coordinate among themselves which program
- can access the tables at which time. See
- <xref linkend="external-locking"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <section id="internal-locking">
-
- <title>Internal Locking Methods</title>
-
- <indexterm>
- <primary>internal locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>internal</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking methods</primary>
- </indexterm>
-
- <indexterm>
- <primary>methods</primary>
- <secondary>locking</secondary>
- </indexterm>
-
- <indexterm>
- <primary>row-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>table-level locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>row-level</secondary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>table-level</secondary>
- </indexterm>
-
- <para>
- This section discusses internal locking; that is, locking
- performed within the MySQL server itself to manage contention
- for table contents by multiple sessions. This type of locking is
- internal because it is performed entirely by the server and
- involves no other programs. External locking occurs when the
- server and other programs lock table files to coordinate among
- themselves which program can access the tables at which time.
- See <xref linkend="external-locking"/>.
- </para>
-
- <para>
- MySQL uses table-level locking for <literal>MyISAM</literal>,
- <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
- and row-level locking for <literal>InnoDB</literal> tables.
- </para>
-
- <para>
- In many cases, you can make an educated guess about which
- locking type is best for an application, but generally it is
- difficult to say that a given lock type is better than another.
- Everything depends on the application and different parts of an
- application may require different lock types.
- </para>
-
- <para>
- To decide whether you want to use a storage engine with
- row-level locking, you should look at what your application does
- and what mix of select and update statements it uses. For
- example, most Web applications perform many selects, relatively
- few deletes, updates based mainly on key values, and inserts
- into a few specific tables. The base MySQL
- <literal>MyISAM</literal> setup is very well tuned for this.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- The MySQL Enterprise Monitor provides expert advice on when to
- use table-level locking and when to use row-level locking. To
- subscribe, see &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
-
- <para>
- Table locking in MySQL is deadlock-free for storage engines that
- use table-level locking. Deadlock avoidance is managed by always
- requesting all needed locks at once at the beginning of a query
- and always locking the tables in the same order.
- </para>
-
- <para>
- MySQL grants table write locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no locks on the table, put a write lock on it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the write lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- MySQL grants table read locks as follows:
- </para>
-
- <orderedlist>
-
- <listitem>
- <para>
- If there are no write locks on the table, put a read lock on
- it.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Otherwise, put the lock request in the read lock queue.
- </para>
- </listitem>
-
- </orderedlist>
-
- <para>
- Table updates are given higher priority than table retrievals.
- Therefore, when a lock is released, the lock is made available
- to the requests in the write lock queue and then to the requests
- in the read lock queue. This ensures that updates to a table are
- not <quote>starved</quote> even if there is heavy
- <literal role="stmt">SELECT</literal> activity for the table.
- However, if you have many updates for a table,
- <literal role="stmt">SELECT</literal> statements wait until
- there are no more updates.
- </para>
-
- <para>
- For information on altering the priority of reads and writes,
- see <xref linkend="table-locking"/>.
- </para>
-
- <para>
- You can analyze the table lock contention on your system by
- checking the
- <literal role="statvar">Table_locks_immediate</literal> and
- <literal role="statvar">Table_locks_waited</literal> status
- variables, which indicate the number of times that requests for
- table locks could be granted immediately and the number that had
- to wait, respectively:
- </para>
-
-<programlisting>
-mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
-+-----------------------+---------+
-| Variable_name | Value |
-+-----------------------+---------+
-| Table_locks_immediate | 1151552 |
-| Table_locks_waited | 15324 |
-+-----------------------+---------+
-</programlisting>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no free
- blocks in the middle of the data file, rows are always inserted
- at the end of the data file. In this case, you can freely mix
- concurrent <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> statements for a
- <literal>MyISAM</literal> table without locks. That is, you can
- insert rows into a <literal>MyISAM</literal> table at the same
- time other clients are reading from it. Holes can result from
- rows having been deleted from or updated in the middle of the
- table. If there are holes, concurrent inserts are disabled but
- are enabled again automatically when all holes have been filled
- with new data.. This behavior is altered by the
- <literal role="sysvar">concurrent_insert</literal> system
- variable. See <xref linkend="concurrent-inserts"/>.
- </para>
-
- <para>
- If you acquire a table lock explicitly with
- <literal role="stmt">LOCK TABLES</literal>, you can request a
- <literal>READ LOCAL</literal> lock rather than a
- <literal>READ</literal> lock to enable other sessions to perform
- concurrent inserts while you have the table locked.
- </para>
-
- <para>
- To perform many <literal role="stmt">INSERT</literal> and
- <literal role="stmt">SELECT</literal> operations on a table
- <literal>real_table</literal> when concurrent inserts are not
- possible, you can insert rows into a temporary table
- <literal>temp_table</literal> and update the real table with the
- rows from the temporary table periodically. This can be done
- with the following code:
- </para>
-
-<programlisting>
-mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
-mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
-mysql> <userinput>DELETE FROM temp_table;</userinput>
-mysql> <userinput>UNLOCK TABLES;</userinput>
-</programlisting>
-
- <para>
- <literal>InnoDB</literal> uses row locks. Deadlocks are possible
- for <literal>InnoDB</literal> because it automatically acquires
- locks during the processing of SQL statements, not at the start
- of the transaction.
- </para>
-
- <para>
- Advantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Fewer lock conflicts when different sessions access
- different rows
- </para>
- </listitem>
-
- <listitem>
- <para>
- Fewer changes for rollbacks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Possible to lock a single row for a long time
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Disadvantages of row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Requires more memory than table-level locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than table-level locks when used on a large part of
- the table because you must acquire many more locks
- </para>
- </listitem>
-
- <listitem>
- <para>
- Slower than other locks if you often do <literal>GROUP
- BY</literal> operations on a large part of the data or if
- you must scan the entire table frequently
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Generally, table locks are superior to row-level locks in the
- following cases:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Most statements for the table are reads
- </para>
- </listitem>
-
- <listitem>
- <para>
- Statements for the table are a mix of reads and writes,
- where writes are updates or deletes for a single row that
- can be fetched with one key read:
- </para>
-
-<programlisting>
-UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
-</programlisting>
- </listitem>
-
- <listitem>
- <para>
- <literal role="stmt">SELECT</literal> combined with
- concurrent <literal role="stmt">INSERT</literal> statements,
- and very few <literal role="stmt">UPDATE</literal> or
- <literal role="stmt">DELETE</literal> statements
- </para>
- </listitem>
-
- <listitem>
- <para>
- Many scans or <literal>GROUP BY</literal> operations on the
- entire table without any writers
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With higher-level locks, you can more easily tune applications
- by supporting locks of different types, because the lock
- overhead is less than for row-level locks.
- </para>
-
- <para>
- Options other than row-level locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Versioning (such as that used in MySQL for concurrent
- inserts) where it is possible to have one writer at the same
- time as many readers. This means that the database or table
- supports different views for the data depending on when
- access begins. Other common terms for this are <quote>time
- travel,</quote> <quote>copy on write,</quote> or <quote>copy
- on demand.</quote>
- </para>
- </listitem>
-
- <listitem>
- <para>
- Copy on demand is in many cases superior to row-level
- locking. However, in the worst case, it can use much more
- memory than using normal locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Instead of using row-level locks, you can employ
- application-level locks, such as those provided by
- <literal role="func">GET_LOCK()</literal> and
- <literal role="func">RELEASE_LOCK()</literal> in MySQL.
- These are advisory locks, so they work only with
- applications that cooperate with each other. See
- <xref linkend="miscellaneous-functions"/>.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="table-locking">
-
- <title>Table Locking Issues</title>
-
- <indexterm>
- <primary>problems</primary>
- <secondary>table locking</secondary>
- </indexterm>
-
- <para>
- To achieve a very high lock speed, MySQL uses table locking
- (instead of page, row, or column locking) for all storage
- engines except <literal>InnoDB</literal>.
- </para>
-
- <para>
- For <literal>InnoDB</literal> tables, MySQL uses table locking
- only if you explicitly lock the table with
- <literal role="stmt">LOCK TABLES</literal>. For this storage
- engine, avoid using <literal role="stmt">LOCK TABLES</literal>
- at all, because <literal>InnoDB</literal> uses automatic
- row-level locking to ensure transaction isolation.
- </para>
-
- <para>
- For large tables, table locking is often better than row
- locking, but there are some disadvantages:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Table locking enables many sessions to read from a table at
- the same time, but if a session wants to write to a table,
- it must first get exclusive access. During the update, all
- other sessions that want to access this particular table
- must wait until the update is done.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Table locking causes problems in cases such as when a
- session is waiting because the disk is full and free space
- needs to become available before the session can proceed. In
- this case, all sessions that want to access the problem
- table are also put in a waiting state until more disk space
- is made available.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Table locking is also disadvantageous under the following
- scenario:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- A session issues a <literal role="stmt">SELECT</literal>
- that takes a long time to run.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session then issues an
- <literal role="stmt">UPDATE</literal> on the same table.
- This session waits until the
- <literal role="stmt">SELECT</literal> is finished.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Another session issues another
- <literal role="stmt">SELECT</literal> statement on the same
- table. Because <literal role="stmt">UPDATE</literal> has
- higher priority than <literal role="stmt">SELECT</literal>,
- this <literal role="stmt">SELECT</literal> waits for the
- <literal role="stmt">UPDATE</literal> to finish,
- <emphasis>after</emphasis> waiting for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The following items describe some ways to avoid or reduce
- contention caused by table locking:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Try to get the <literal role="stmt">SELECT</literal>
- statements to run faster so that they lock tables for a
- shorter time. You might have to create some summary tables
- to do this.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with
- <option role="mysqld">--low-priority-updates</option>. For
- storage engines that use only table-level locking (such as
- <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
- <literal>MERGE</literal>), this gives all statements that
- update (modify) a table lower priority than
- <literal role="stmt">SELECT</literal> statements. In this
- case, the second <literal role="stmt">SELECT</literal>
- statement in the preceding scenario would execute before the
- <literal role="stmt">UPDATE</literal> statement, and would
- not need to wait for the first
- <literal role="stmt">SELECT</literal> to finish.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To specify that all updates issued in a specific connection
- should be done with low priority, set the
- <literal role="sysvar">low_priority_updates</literal> server
- system variable equal to 1.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">INSERT</literal>,
- <literal role="stmt">UPDATE</literal>, or
- <literal role="stmt">DELETE</literal> statement lower
- priority, use the <literal>LOW_PRIORITY</literal> attribute.
- </para>
- </listitem>
-
- <listitem>
- <para>
- To give a specific <literal role="stmt">SELECT</literal>
- statement higher priority, use the
- <literal>HIGH_PRIORITY</literal> attribute. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Start <command>mysqld</command> with a low value for the
- <literal role="sysvar">max_write_lock_count</literal> system
- variable to force MySQL to temporarily elevate the priority
- of all <literal role="stmt">SELECT</literal> statements that
- are waiting for a table after a specific number of inserts
- to the table occur. This permits <literal>READ</literal>
- locks after a certain number of <literal>WRITE</literal>
- locks.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with
- <literal role="stmt">INSERT</literal> combined with
- <literal role="stmt">SELECT</literal>, consider switching to
- <literal>MyISAM</literal> tables, which support concurrent
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">INSERT</literal> statements. (See
- <xref linkend="concurrent-inserts"/>.)
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you mix inserts and deletes on the same table,
- <literal role="stmt">INSERT DELAYED</literal> may be of
- great help. See <xref linkend="insert-delayed"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you have problems with mixed
- <literal role="stmt">SELECT</literal> and
- <literal role="stmt">DELETE</literal> statements, the
- <literal>LIMIT</literal> option to
- <literal role="stmt">DELETE</literal> may help. See
- <xref linkend="delete"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Using <literal>SQL_BUFFER_RESULT</literal> with
- <literal role="stmt">SELECT</literal> statements can help to
- make the duration of table locks shorter. See
- <xref linkend="select"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You could change the locking code in
- <filename>mysys/thr_lock.c</filename> to use a single queue.
- In this case, write locks and read locks would have the same
- priority, which might help some applications.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- Here are some tips concerning table locks in MySQL:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Concurrent users are not a problem if you do not mix updates
- with selects that need to examine many rows in the same
- table.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You can use <literal role="stmt">LOCK TABLES</literal> to
- increase speed, because many updates within a single lock is
- much faster than updating without locks. Splitting table
- contents into separate tables may also help.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you encounter speed problems with table locks in MySQL,
- you may be able to improve performance by converting some of
- your tables to <literal>InnoDB</literal>. See
- <xref linkend="innodb"/>.
- </para>
-
- <formalpara role="mnmas">
-
- <title>MySQL Enterprise</title>
-
- <para>
- Lock contention can seriously degrade performance. The
- MySQL Enterprise Monitor provides expert advice on
- avoiding this problem. To subscribe, see
- &base-url-enterprise;advisors.html.
- </para>
-
- </formalpara>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="concurrent-inserts">
-
- <title>Concurrent Inserts</title>
-
- <indexterm>
- <primary>concurrent inserts</primary>
- </indexterm>
-
- <indexterm>
- <primary>inserts</primary>
- <secondary>concurrent</secondary>
- </indexterm>
-
- <para>
- The <literal>MyISAM</literal> storage engine supports concurrent
- inserts to reduce contention between readers and writers for a
- given table: If a <literal>MyISAM</literal> table has no holes
- in the data file (deleted rows in the middle), an
- <literal role="stmt">INSERT</literal> statement can be executed
- to add rows to the end of the table at the same time that
- <literal role="stmt">SELECT</literal> statements are reading
- rows from the table. If there are multiple
- <literal role="stmt">INSERT</literal> statements, they are
- queued and performed in sequence, concurrently with the
- <literal role="stmt">SELECT</literal> statements. The results of
- a concurrent <literal role="stmt">INSERT</literal> may not be
- visible immediately.
- </para>
-
- <para>
- The <literal role="sysvar">concurrent_insert</literal> system
- variable can be set to modify the concurrent-insert processing.
- By default, the variable is set to <literal>AUTO</literal> (or
- 1) and concurrent inserts are handled as just described. If
- <literal role="sysvar">concurrent_insert</literal> is set to
- <literal>NEVER</literal> (or 0), concurrent inserts are
- disabled. If the variable is set to <literal>ALWAYS</literal>
- (or 2), concurrent inserts at the end of the table are allowed
- even for tables that have deleted rows. See also the description
- of the
- <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
- system variable.
- </para>
-
- <para>
- Under circumstances where concurrent inserts can be used, there
- is seldom any need to use the <literal>DELAYED</literal>
- modifier for <literal role="stmt">INSERT</literal> statements.
- See <xref linkend="insert-delayed"/>.
- </para>
-
- <para>
- If you are using the binary log, concurrent inserts are
- converted to normal inserts for <literal>CREATE ...
- SELECT</literal> or
- <literal role="stmt" condition="insert-select">INSERT ...
- SELECT</literal> statements. This is done to ensure that you can
- re-create an exact copy of your tables by applying the log
- during a backup operation. See <xref linkend="binary-log"/>. In
- addition, for those statements a read lock is placed on the
- selected-from table such that inserts into that table are
- blocked. The effect is that concurrent inserts for that table
- must wait as well.
- </para>
-
- <para>
- With <literal role="stmt" condition="load-data">LOAD DATA
- INFILE</literal>, if you specify <literal>CONCURRENT</literal>
- with a <literal>MyISAM</literal> table that satisfies the
- condition for concurrent inserts (that is, it contains no free
- blocks in the middle), other sessions can retrieve data from the
- table while <literal role="stmt">LOAD DATA</literal> is
- executing. Use of the <literal>CONCURRENT</literal> option
- affects the performance of <literal role="stmt">LOAD
- DATA</literal> a bit, even if no other session is using the
- table at the same time.
- </para>
-
- <para>
- If you specify <literal>HIGH_PRIORITY</literal>, it overrides
- the effect of the
- <option role="mysqld">--low-priority-updates</option> option if
- the server was started with that option. It also causes
- concurrent inserts not to be used.
- </para>
-
- <para>
- For <literal role="stmt" condition="lock-tables">LOCK
- TABLE</literal>, the difference between <literal>READ
- LOCAL</literal> and <literal>READ</literal> is that
- <literal>READ LOCAL</literal> permits nonconflicting
- <literal role="stmt">INSERT</literal> statements (concurrent
- inserts) to execute while the lock is held. However, this cannot
- be used if you are going to manipulate the database using
- processes external to the server while you hold the lock.
- </para>
-
- </section>
-
- <section id="metadata-locking">
-
- <title>Metadata Locking Within Transactions</title>
-
- <indexterm>
- <primary>metadata locking</primary>
- <secondary>transactions</secondary>
- </indexterm>
-
- <indexterm>
- <primary>transactions</primary>
- <secondary>metadata locking</secondary>
- </indexterm>
-
- <para>
- To ensure transaction serializability, the server must not allow
- one session to perform a data definition language (DDL)
- statement on a table that is used in an uncompleted transaction
- in another session.
- </para>
-
- <para>
- As of MySQL 6.0.11, the server achieves this by acquiring
- metadata locks on tables used within a transaction and deferring
- release of those locks until the transaction ends. A metadata
- lock on a table prevents changes to the table's structure. This
- locking approach has the implication that a table that is being
- used by a transaction within one session cannot be used in DDL
- statements by other sessions until the transaction ends. For
- example, if a table <literal>t1</literal> is in use by a
- transaction, another session that attempts to execute
- <literal role="stmt" condition="drop-table">DROP TABLE
- t1</literal> will block until the transaction ends.
- </para>
-
- <para>
- If the server acquires metadata locks for a statement that is
- syntactically valid but fails during execution, it does not
- release the locks early. Lock release is still deferred to the
- end of the transaction because the failed statement is written
- to the binary log and the locks protect log consistency.
- </para>
-
- <para>
- Metadata locks acquired during a
- <literal role="stmt">PREPARE</literal> statement are released
- once the statement has been prepared, even if preparation occurs
- within a multiple-statement transaction.
- </para>
-
- <para>
- Before MySQL 6.0.11, when a transaction acquired a metadata lock
- for a table used within a statement, it released the lock at the
- end of the statement. This approach had the disadvantage that if
- a DDL statement occurred for a table that was being used by
- another session in an active transaction, statements could be
- written to the binary log in the wrong order.
- </para>
-
- </section>
-
- <section id="external-locking">
-
- <title>External Locking</title>
-
- <indexterm>
- <primary>external locking</primary>
- </indexterm>
-
- <indexterm>
- <primary>locking</primary>
- <secondary>external</secondary>
- </indexterm>
-
- <para>
- External locking is the use of file system locking to manage
- contention for database tables by multiple processes. External
- locking is used in situations where a single process such as the
- MySQL server cannot be assumed to be the only process that
- requires access to tables. Here are some examples:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- If you run multiple servers that use the same database
- directory (not recommended), each server must have external
- locking enabled.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If you use <command>myisamchk</command> to perform table
- maintenance operations on <literal>MyISAM</literal> tables,
- you must either ensure that the server is not running, or
- that the server has external locking enabled so that it
- locks table files as necessary to coordinate with
- <command>myisamchk</command> for access to the tables. The
- same is true for use of <command>myisampack</command> to
- pack <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- If the server is run with external locking enabled, you can
- use <command>myisamchk</command> at any time for read
- operations such a checking tables. In this case, if the
- server tries to update a table that
- <command>myisamchk</command> is using, the server will wait
- for <command>myisamchk</command> to finish before it
- continues.
- </para>
-
- <para>
- If you use <command>myisamchk</command> for write operations
- such as repairing or optimizing tables, or if you use
- <command>myisampack</command> to pack tables, you
- <emphasis>must</emphasis> always ensure that the
- <command>mysqld</command> server is not using the table. If
- you don't stop <command>mysqld</command>, you should at
- least do a <command>mysqladmin flush-tables</command> before
- you run <command>myisamchk</command>. Your tables
- <emphasis>may become corrupted</emphasis> if the server and
- <command>myisamchk</command> access the tables
- simultaneously.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- With external locking in effect, each process that requires
- access to a table acquires a file system lock for the table
- files before proceeding to access the table. If all necessary
- locks cannot be acquired, the process is blocked from accessing
- the table until the locks can be obtained (after the process
- that currently holds the locks releases them).
- </para>
-
- <para>
- External locking affects server performance because the server
- must sometimes wait for other processes before it can access
- tables.
- </para>
-
- <para>
- External locking is unnecessary if you run a single server to
- access a given data directory (which is the usual case) and if
- no other programs such as <command>myisamchk</command> need to
- modify tables while the server is running. If you only
- <emphasis>read</emphasis> tables with other programs, external
- locking is not required, although <command>myisamchk</command>
- might report warnings if the server changes tables while
- <command>myisamchk</command> is reading them.
- </para>
-
- <para>
- With external locking disabled, to use
- <command>myisamchk</command>, you must either stop the server
- while <command>myisamchk</command> executes or else lock and
- flush the tables before running <command>myisamchk</command>.
- (See <xref linkend="system-optimization"/>.) To avoid this
- requirement, use the <literal role="stmt">CHECK TABLE</literal>
- and <literal role="stmt">REPAIR TABLE</literal> statements to
- check and repair <literal>MyISAM</literal> tables.
- </para>
-
- <para>
- For <command>mysqld</command>, external locking is controlled by
- the value of the
- <literal role="sysvar">skip_external_locking</literal> system
- variable. When this variable is enabled, external locking is
- disabled, and vice versa. From MySQL 4.0 on, external locking is
- disabled by default. Before MySQL 4.0, external locking is
- enabled by default on Linux or when MySQL is configured to use
- MIT-pthreads.
- </para>
-
- <para>
- Use of external locking can be controlled at server startup by
- using the <option role="mysqld">--external-locking</option> or
- <option role="mysqld">--skip-external-locking</option> option.
- </para>
-
- <para>
- If you do use external locking option to enable updates to
- <literal>MyISAM</literal> tables from many MySQL processes, you
- must ensure that the following conditions are satisfied:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- You should not use the query cache for queries that use
- tables that are updated by another process.
- </para>
- </listitem>
-
- <listitem>
- <para>
- You should not start the server with the
- <option role="mysqld">--delay-key-write=ALL</option> option
- or use the <literal>DELAY_KEY_WRITE=1</literal> table option
- for any shared tables. Otherwise, index corruption can
- occur.
- </para>
- </listitem>
-
- </itemizedlist>
-
- <para>
- The easiest way to satisfy these conditions is to always use
- <option role="mysqld">--external-locking</option> together with
- <option role="mysqld">--delay-key-write=OFF</option> and
- <option role="sysvar">--query-cache-size=0</option>. (This is
- not done by default because in many setups it is useful to have
- a mixture of the preceding options.)
- </para>
-
- </section>
-
- </section>
-
- <section id="optimizing-database-structure">
-
- <title>Optimizing Database Structure</title>
-
- <section id="data-size">
-
- <title>Make Your Data as Small as Possible</title>
-
- <indexterm>
- <primary>data</primary>
- <secondary>size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>reducing</primary>
- <secondary>data size</secondary>
- </indexterm>
-
- <indexterm>
- <primary>storage space</primary>
- <secondary>minimizing</secondary>
- </indexterm>
-
- <indexterm>
- <primary>tables</primary>
- <secondary>improving performance</secondary>
- </indexterm>
-
- <indexterm>
- <primary>performance</primary>
- <secondary>improving</secondary>
- </indexterm>
-
- <para>
- One of the most basic optimizations is to design your tables to
- take as little space on the disk as possible. This can result in
- huge improvements because disk reads are faster, and smaller
- tables normally require less main memory while their contents
- are being actively processed during query execution. Indexing
- also is a lesser resource burden if done on smaller columns.
- </para>
-
- <para>
- MySQL supports many different storage engines (table types) and
- row formats. For each table, you can decide which storage and
- indexing method to use. Choosing the proper table format for
- your application may give you a big performance gain. See
- <xref linkend="storage-engines"/>.
- </para>
-
- <para>
- You can get better performance for a table and minimize storage
- space by using the techniques listed here:
- </para>
-
- <itemizedlist>
-
- <listitem>
- <para>
- Use the most efficient (smallest) data types possible. MySQL
- has many specialized types that save disk space and memory.
- For example, use the smaller integer types if possible to
- get smaller tables. <literal role="type">MEDIUMINT</literal>
- is often a better choice than
- <literal role="type">INT</literal> because a
- <literal role="type">MEDIUMINT</literal> column uses 25%
- less space.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Declare columns to be <literal>NOT NULL</literal> if
- possible. It makes everything faster and you save one bit
- per column. If you really need <literal>NULL</literal> in
- your application, you should definitely use it. Just avoid
- having it on all columns by default.
- </para>
- </listitem>
-
- <listitem>
- <para>
- For <literal>MyISAM</literal> tables, if you do not have any
- variable-length columns
- (<literal role="type">VARCHAR</literal>,
- <literal role="type">TEXT</literal>, or
- <literal role="type">BLOB</literal> columns), a fixed-size
- row format is used. This is faster but unfortunately may
- waste some space. See
- <xref linkend="myisam-table-formats"/>. You can hint that
- you want to have fixed length rows even if you have
- <literal role="type">VARCHAR</literal> columns with the
- <literal role="stmt">CREATE TABLE</literal> option
- <literal>ROW_FORMAT=FIXED</literal>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- <literal>InnoDB</literal> tables use a compact storage
- format. In versions of MySQL earlier than 5.0.3,
- <literal>InnoDB</literal> rows contain some redundant
- information, such as the number of columns and the length of
- each column, even for fixed-size columns. By default, tables
- are created in the compact format
- (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
- downgrade to older versions of MySQL, you can request the
- old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
- </para>
-
- <para>
- The presence of the compact row format decreases row storage
- space by about 20% at the cost of increasing CPU use for
- some operations. If your workload is a typical one that is
- limited by cache hit rates and disk speed it is likely to be
- faster. If it is a rare case that is limited by CPU speed,
- it might be slower.
- </para>
-
- <para>
- The compact <literal>InnoDB</literal> format also changes
- how <literal role="type">CHAR</literal> columns containing
- UTF-8 data are stored. With
- <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
- <literal>CHAR(<replaceable>N</replaceable>)</literal>
- occupies 3 × <replaceable>N</replaceable> bytes, given
- that the maximum length of a UTF-8 encoded character is
- three bytes. Many languages can be written primarily using
- single-byte UTF-8 characters, so a fixed storage length
- often wastes space. With
- <literal>ROW_FORMAT=COMPACT</literal> format,
- <literal>InnoDB</literal> allocates a variable amount of
- storage in the range from <replaceable>N</replaceable> to 3
- × <replaceable>N</replaceable> bytes for these columns
- by stripping trailing spaces if necessary. The minimum
- storage length is kept as <replaceable>N</replaceable> bytes
- to facilitate in-place updates in typical cases.
- </para>
- </listitem>
-
- <listitem>
- <para>
- The primary index of a table should be as short as possible.
- This makes identification of each row easy and efficient.
- </para>
- </listitem>
-
- <listitem>
- <para>
- Create only the indexes that you really need. Indexes are
- good for retrieval but bad when you need to store data
- quickly. If you access a table mostly by searching on a
- combination of columns, create an index on them. The first
- part of the index should be the column most used. If you
- <emphasis>always</emphasis> use many columns when selecting
- from the table, the first column in the index should be the
- one with the most duplicates to obtain better compression of
- the index.
- </para>
- </listitem>
-
- <listitem>
- <para>
- If it is very likely that a string column has a unique
- prefix on the first number of characters, it is better to
- index only this prefix, using MySQL's support for creating
- an index on the leftmost part of the column (see
- <xref linkend="create-index"/>). Shorter indexes are faster,
- not only because they require less disk space, but because
- they also give you more hits in the index cache, and thus
- fewer disk seeks. See <xref linkend="server-parameters"/>.
- </para>
- </listitem>
-
- <listitem>
- <para>
- In some circumstances, it can be beneficial to split into
- two a table that is scanned very often. This is especially
- true if it is a dynamic-format table and it is possible to
- use a smaller static format table that can be used to find
- the relevant rows when scanning the table.
- </para>
- </listitem>
-
- </itemizedlist>
-
- </section>
-
- <section id="indexes">
-
<title>Column Indexes</title>
<indexterm>
@@ -11247,7 +10063,7 @@
MySQL can create composite indexes (that is, indexes on multiple
columns). An index may consist of up to 16 columns. For certain
data types, you can index a prefix of the column (see
- <xref linkend="indexes"/>).
+ <xref linkend="column-indexes"/>).
</para>
<para>
@@ -12756,6 +11572,1196 @@
</section>
+ </section>
+
+ <section id="locking-issues">
+
+ <title>Locking Issues</title>
+
+ <para>
+ MySQL manages contention for table contents using locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Internal locking is performed within the MySQL server itself
+ to manage contention for table contents by multiple threads.
+ This type of locking is internal because it is performed
+ entirely by the server and involves no other programs. See
+ <xref linkend="internal-locking"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ External locking occurs when the server and other programs
+ lock table files to coordinate among themselves which program
+ can access the tables at which time. See
+ <xref linkend="external-locking"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <section id="internal-locking">
+
+ <title>Internal Locking Methods</title>
+
+ <indexterm>
+ <primary>internal locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>internal</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking methods</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>methods</primary>
+ <secondary>locking</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>table-level locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>row-level</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>table-level</secondary>
+ </indexterm>
+
+ <para>
+ This section discusses internal locking; that is, locking
+ performed within the MySQL server itself to manage contention
+ for table contents by multiple sessions. This type of locking is
+ internal because it is performed entirely by the server and
+ involves no other programs. External locking occurs when the
+ server and other programs lock table files to coordinate among
+ themselves which program can access the tables at which time.
+ See <xref linkend="external-locking"/>.
+ </para>
+
+ <para>
+ MySQL uses table-level locking for <literal>MyISAM</literal>,
+ <literal>MEMORY</literal>, and <literal>MERGE</literal> tables,
+ and row-level locking for <literal>InnoDB</literal> tables.
+ </para>
+
+ <para>
+ In many cases, you can make an educated guess about which
+ locking type is best for an application, but generally it is
+ difficult to say that a given lock type is better than another.
+ Everything depends on the application and different parts of an
+ application may require different lock types.
+ </para>
+
+ <para>
+ To decide whether you want to use a storage engine with
+ row-level locking, you should look at what your application does
+ and what mix of select and update statements it uses. For
+ example, most Web applications perform many selects, relatively
+ few deletes, updates based mainly on key values, and inserts
+ into a few specific tables. The base MySQL
+ <literal>MyISAM</literal> setup is very well tuned for this.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ The MySQL Enterprise Monitor provides expert advice on when to
+ use table-level locking and when to use row-level locking. To
+ subscribe, see &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+
+ <para>
+ Table locking in MySQL is deadlock-free for storage engines that
+ use table-level locking. Deadlock avoidance is managed by always
+ requesting all needed locks at once at the beginning of a query
+ and always locking the tables in the same order.
+ </para>
+
+ <para>
+ MySQL grants table write locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no locks on the table, put a write lock on it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the write lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ MySQL grants table read locks as follows:
+ </para>
+
+ <orderedlist>
+
+ <listitem>
+ <para>
+ If there are no write locks on the table, put a read lock on
+ it.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Otherwise, put the lock request in the read lock queue.
+ </para>
+ </listitem>
+
+ </orderedlist>
+
+ <para>
+ Table updates are given higher priority than table retrievals.
+ Therefore, when a lock is released, the lock is made available
+ to the requests in the write lock queue and then to the requests
+ in the read lock queue. This ensures that updates to a table are
+ not <quote>starved</quote> even if there is heavy
+ <literal role="stmt">SELECT</literal> activity for the table.
+ However, if you have many updates for a table,
+ <literal role="stmt">SELECT</literal> statements wait until
+ there are no more updates.
+ </para>
+
+ <para>
+ For information on altering the priority of reads and writes,
+ see <xref linkend="table-locking"/>.
+ </para>
+
+ <para>
+ You can analyze the table lock contention on your system by
+ checking the
+ <literal role="statvar">Table_locks_immediate</literal> and
+ <literal role="statvar">Table_locks_waited</literal> status
+ variables, which indicate the number of times that requests for
+ table locks could be granted immediately and the number that had
+ to wait, respectively:
+ </para>
+
+<programlisting>
+mysql> <userinput>SHOW STATUS LIKE 'Table%';</userinput>
++-----------------------+---------+
+| Variable_name | Value |
++-----------------------+---------+
+| Table_locks_immediate | 1151552 |
+| Table_locks_waited | 15324 |
++-----------------------+---------+
+</programlisting>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no free
+ blocks in the middle of the data file, rows are always inserted
+ at the end of the data file. In this case, you can freely mix
+ concurrent <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> statements for a
+ <literal>MyISAM</literal> table without locks. That is, you can
+ insert rows into a <literal>MyISAM</literal> table at the same
+ time other clients are reading from it. Holes can result from
+ rows having been deleted from or updated in the middle of the
+ table. If there are holes, concurrent inserts are disabled but
+ are enabled again automatically when all holes have been filled
+ with new data.. This behavior is altered by the
+ <literal role="sysvar">concurrent_insert</literal> system
+ variable. See <xref linkend="concurrent-inserts"/>.
+ </para>
+
+ <para>
+ If you acquire a table lock explicitly with
+ <literal role="stmt">LOCK TABLES</literal>, you can request a
+ <literal>READ LOCAL</literal> lock rather than a
+ <literal>READ</literal> lock to enable other sessions to perform
+ concurrent inserts while you have the table locked.
+ </para>
+
+ <para>
+ To perform many <literal role="stmt">INSERT</literal> and
+ <literal role="stmt">SELECT</literal> operations on a table
+ <literal>real_table</literal> when concurrent inserts are not
+ possible, you can insert rows into a temporary table
+ <literal>temp_table</literal> and update the real table with the
+ rows from the temporary table periodically. This can be done
+ with the following code:
+ </para>
+
+<programlisting>
+mysql> <userinput>LOCK TABLES real_table WRITE, temp_table WRITE;</userinput>
+mysql> <userinput>INSERT INTO real_table SELECT * FROM temp_table;</userinput>
+mysql> <userinput>DELETE FROM temp_table;</userinput>
+mysql> <userinput>UNLOCK TABLES;</userinput>
+</programlisting>
+
+ <para>
+ <literal>InnoDB</literal> uses row locks. Deadlocks are possible
+ for <literal>InnoDB</literal> because it automatically acquires
+ locks during the processing of SQL statements, not at the start
+ of the transaction.
+ </para>
+
+ <para>
+ Advantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Fewer lock conflicts when different sessions access
+ different rows
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Fewer changes for rollbacks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Possible to lock a single row for a long time
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Disadvantages of row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Requires more memory than table-level locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than table-level locks when used on a large part of
+ the table because you must acquire many more locks
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Slower than other locks if you often do <literal>GROUP
+ BY</literal> operations on a large part of the data or if
+ you must scan the entire table frequently
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Generally, table locks are superior to row-level locks in the
+ following cases:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Most statements for the table are reads
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Statements for the table are a mix of reads and writes,
+ where writes are updates or deletes for a single row that
+ can be fetched with one key read:
+ </para>
+
+<programlisting>
+UPDATE <replaceable>tbl_name</replaceable> SET <replaceable>column</replaceable>=<replaceable>value</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+DELETE FROM <replaceable>tbl_name</replaceable> WHERE <replaceable>unique_key_col</replaceable>=<replaceable>key_value</replaceable>;
+</programlisting>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal role="stmt">SELECT</literal> combined with
+ concurrent <literal role="stmt">INSERT</literal> statements,
+ and very few <literal role="stmt">UPDATE</literal> or
+ <literal role="stmt">DELETE</literal> statements
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Many scans or <literal>GROUP BY</literal> operations on the
+ entire table without any writers
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With higher-level locks, you can more easily tune applications
+ by supporting locks of different types, because the lock
+ overhead is less than for row-level locks.
+ </para>
+
+ <para>
+ Options other than row-level locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Versioning (such as that used in MySQL for concurrent
+ inserts) where it is possible to have one writer at the same
+ time as many readers. This means that the database or table
+ supports different views for the data depending on when
+ access begins. Other common terms for this are <quote>time
+ travel,</quote> <quote>copy on write,</quote> or <quote>copy
+ on demand.</quote>
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Copy on demand is in many cases superior to row-level
+ locking. However, in the worst case, it can use much more
+ memory than using normal locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Instead of using row-level locks, you can employ
+ application-level locks, such as those provided by
+ <literal role="func">GET_LOCK()</literal> and
+ <literal role="func">RELEASE_LOCK()</literal> in MySQL.
+ These are advisory locks, so they work only with
+ applications that cooperate with each other. See
+ <xref linkend="miscellaneous-functions"/>.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="table-locking">
+
+ <title>Table Locking Issues</title>
+
+ <indexterm>
+ <primary>problems</primary>
+ <secondary>table locking</secondary>
+ </indexterm>
+
+ <para>
+ To achieve a very high lock speed, MySQL uses table locking
+ (instead of page, row, or column locking) for all storage
+ engines except <literal>InnoDB</literal>.
+ </para>
+
+ <para>
+ For <literal>InnoDB</literal> tables, MySQL uses table locking
+ only if you explicitly lock the table with
+ <literal role="stmt">LOCK TABLES</literal>. For this storage
+ engine, avoid using <literal role="stmt">LOCK TABLES</literal>
+ at all, because <literal>InnoDB</literal> uses automatic
+ row-level locking to ensure transaction isolation.
+ </para>
+
+ <para>
+ For large tables, table locking is often better than row
+ locking, but there are some disadvantages:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Table locking enables many sessions to read from a table at
+ the same time, but if a session wants to write to a table,
+ it must first get exclusive access. During the update, all
+ other sessions that want to access this particular table
+ must wait until the update is done.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Table locking causes problems in cases such as when a
+ session is waiting because the disk is full and free space
+ needs to become available before the session can proceed. In
+ this case, all sessions that want to access the problem
+ table are also put in a waiting state until more disk space
+ is made available.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Table locking is also disadvantageous under the following
+ scenario:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ A session issues a <literal role="stmt">SELECT</literal>
+ that takes a long time to run.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session then issues an
+ <literal role="stmt">UPDATE</literal> on the same table.
+ This session waits until the
+ <literal role="stmt">SELECT</literal> is finished.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Another session issues another
+ <literal role="stmt">SELECT</literal> statement on the same
+ table. Because <literal role="stmt">UPDATE</literal> has
+ higher priority than <literal role="stmt">SELECT</literal>,
+ this <literal role="stmt">SELECT</literal> waits for the
+ <literal role="stmt">UPDATE</literal> to finish,
+ <emphasis>after</emphasis> waiting for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The following items describe some ways to avoid or reduce
+ contention caused by table locking:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Try to get the <literal role="stmt">SELECT</literal>
+ statements to run faster so that they lock tables for a
+ shorter time. You might have to create some summary tables
+ to do this.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with
+ <option role="mysqld">--low-priority-updates</option>. For
+ storage engines that use only table-level locking (such as
+ <literal>MyISAM</literal>, <literal>MEMORY</literal>, and
+ <literal>MERGE</literal>), this gives all statements that
+ update (modify) a table lower priority than
+ <literal role="stmt">SELECT</literal> statements. In this
+ case, the second <literal role="stmt">SELECT</literal>
+ statement in the preceding scenario would execute before the
+ <literal role="stmt">UPDATE</literal> statement, and would
+ not need to wait for the first
+ <literal role="stmt">SELECT</literal> to finish.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To specify that all updates issued in a specific connection
+ should be done with low priority, set the
+ <literal role="sysvar">low_priority_updates</literal> server
+ system variable equal to 1.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">INSERT</literal>,
+ <literal role="stmt">UPDATE</literal>, or
+ <literal role="stmt">DELETE</literal> statement lower
+ priority, use the <literal>LOW_PRIORITY</literal> attribute.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ To give a specific <literal role="stmt">SELECT</literal>
+ statement higher priority, use the
+ <literal>HIGH_PRIORITY</literal> attribute. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Start <command>mysqld</command> with a low value for the
+ <literal role="sysvar">max_write_lock_count</literal> system
+ variable to force MySQL to temporarily elevate the priority
+ of all <literal role="stmt">SELECT</literal> statements that
+ are waiting for a table after a specific number of inserts
+ to the table occur. This permits <literal>READ</literal>
+ locks after a certain number of <literal>WRITE</literal>
+ locks.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with
+ <literal role="stmt">INSERT</literal> combined with
+ <literal role="stmt">SELECT</literal>, consider switching to
+ <literal>MyISAM</literal> tables, which support concurrent
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">INSERT</literal> statements. (See
+ <xref linkend="concurrent-inserts"/>.)
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you mix inserts and deletes on the same table,
+ <literal role="stmt">INSERT DELAYED</literal> may be of
+ great help. See <xref linkend="insert-delayed"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you have problems with mixed
+ <literal role="stmt">SELECT</literal> and
+ <literal role="stmt">DELETE</literal> statements, the
+ <literal>LIMIT</literal> option to
+ <literal role="stmt">DELETE</literal> may help. See
+ <xref linkend="delete"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Using <literal>SQL_BUFFER_RESULT</literal> with
+ <literal role="stmt">SELECT</literal> statements can help to
+ make the duration of table locks shorter. See
+ <xref linkend="select"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You could change the locking code in
+ <filename>mysys/thr_lock.c</filename> to use a single queue.
+ In this case, write locks and read locks would have the same
+ priority, which might help some applications.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ Here are some tips concerning table locks in MySQL:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Concurrent users are not a problem if you do not mix updates
+ with selects that need to examine many rows in the same
+ table.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You can use <literal role="stmt">LOCK TABLES</literal> to
+ increase speed, because many updates within a single lock is
+ much faster than updating without locks. Splitting table
+ contents into separate tables may also help.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you encounter speed problems with table locks in MySQL,
+ you may be able to improve performance by converting some of
+ your tables to <literal>InnoDB</literal>. See
+ <xref linkend="innodb"/>.
+ </para>
+
+ <formalpara role="mnmas">
+
+ <title>MySQL Enterprise</title>
+
+ <para>
+ Lock contention can seriously degrade performance. The
+ MySQL Enterprise Monitor provides expert advice on
+ avoiding this problem. To subscribe, see
+ &base-url-enterprise;advisors.html.
+ </para>
+
+ </formalpara>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
+ <section id="concurrent-inserts">
+
+ <title>Concurrent Inserts</title>
+
+ <indexterm>
+ <primary>concurrent inserts</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>inserts</primary>
+ <secondary>concurrent</secondary>
+ </indexterm>
+
+ <para>
+ The <literal>MyISAM</literal> storage engine supports concurrent
+ inserts to reduce contention between readers and writers for a
+ given table: If a <literal>MyISAM</literal> table has no holes
+ in the data file (deleted rows in the middle), an
+ <literal role="stmt">INSERT</literal> statement can be executed
+ to add rows to the end of the table at the same time that
+ <literal role="stmt">SELECT</literal> statements are reading
+ rows from the table. If there are multiple
+ <literal role="stmt">INSERT</literal> statements, they are
+ queued and performed in sequence, concurrently with the
+ <literal role="stmt">SELECT</literal> statements. The results of
+ a concurrent <literal role="stmt">INSERT</literal> may not be
+ visible immediately.
+ </para>
+
+ <para>
+ The <literal role="sysvar">concurrent_insert</literal> system
+ variable can be set to modify the concurrent-insert processing.
+ By default, the variable is set to <literal>AUTO</literal> (or
+ 1) and concurrent inserts are handled as just described. If
+ <literal role="sysvar">concurrent_insert</literal> is set to
+ <literal>NEVER</literal> (or 0), concurrent inserts are
+ disabled. If the variable is set to <literal>ALWAYS</literal>
+ (or 2), concurrent inserts at the end of the table are allowed
+ even for tables that have deleted rows. See also the description
+ of the
+ <link linkend="sysvar_concurrent_insert"><literal role="sysvar">concurrent_insert</literal></link>
+ system variable.
+ </para>
+
+ <para>
+ Under circumstances where concurrent inserts can be used, there
+ is seldom any need to use the <literal>DELAYED</literal>
+ modifier for <literal role="stmt">INSERT</literal> statements.
+ See <xref linkend="insert-delayed"/>.
+ </para>
+
+ <para>
+ If you are using the binary log, concurrent inserts are
+ converted to normal inserts for <literal>CREATE ...
+ SELECT</literal> or
+ <literal role="stmt" condition="insert-select">INSERT ...
+ SELECT</literal> statements. This is done to ensure that you can
+ re-create an exact copy of your tables by applying the log
+ during a backup operation. See <xref linkend="binary-log"/>. In
+ addition, for those statements a read lock is placed on the
+ selected-from table such that inserts into that table are
+ blocked. The effect is that concurrent inserts for that table
+ must wait as well.
+ </para>
+
+ <para>
+ With <literal role="stmt" condition="load-data">LOAD DATA
+ INFILE</literal>, if you specify <literal>CONCURRENT</literal>
+ with a <literal>MyISAM</literal> table that satisfies the
+ condition for concurrent inserts (that is, it contains no free
+ blocks in the middle), other sessions can retrieve data from the
+ table while <literal role="stmt">LOAD DATA</literal> is
+ executing. Use of the <literal>CONCURRENT</literal> option
+ affects the performance of <literal role="stmt">LOAD
+ DATA</literal> a bit, even if no other session is using the
+ table at the same time.
+ </para>
+
+ <para>
+ If you specify <literal>HIGH_PRIORITY</literal>, it overrides
+ the effect of the
+ <option role="mysqld">--low-priority-updates</option> option if
+ the server was started with that option. It also causes
+ concurrent inserts not to be used.
+ </para>
+
+ <para>
+ For <literal role="stmt" condition="lock-tables">LOCK
+ TABLE</literal>, the difference between <literal>READ
+ LOCAL</literal> and <literal>READ</literal> is that
+ <literal>READ LOCAL</literal> permits nonconflicting
+ <literal role="stmt">INSERT</literal> statements (concurrent
+ inserts) to execute while the lock is held. However, this cannot
+ be used if you are going to manipulate the database using
+ processes external to the server while you hold the lock.
+ </para>
+
+ </section>
+
+ <section id="metadata-locking">
+
+ <title>Metadata Locking Within Transactions</title>
+
+ <indexterm>
+ <primary>metadata locking</primary>
+ <secondary>transactions</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>transactions</primary>
+ <secondary>metadata locking</secondary>
+ </indexterm>
+
+ <para>
+ To ensure transaction serializability, the server must not allow
+ one session to perform a data definition language (DDL)
+ statement on a table that is used in an uncompleted transaction
+ in another session.
+ </para>
+
+ <para>
+ As of MySQL 6.0.11, the server achieves this by acquiring
+ metadata locks on tables used within a transaction and deferring
+ release of those locks until the transaction ends. A metadata
+ lock on a table prevents changes to the table's structure. This
+ locking approach has the implication that a table that is being
+ used by a transaction within one session cannot be used in DDL
+ statements by other sessions until the transaction ends. For
+ example, if a table <literal>t1</literal> is in use by a
+ transaction, another session that attempts to execute
+ <literal role="stmt" condition="drop-table">DROP TABLE
+ t1</literal> will block until the transaction ends.
+ </para>
+
+ <para>
+ If the server acquires metadata locks for a statement that is
+ syntactically valid but fails during execution, it does not
+ release the locks early. Lock release is still deferred to the
+ end of the transaction because the failed statement is written
+ to the binary log and the locks protect log consistency.
+ </para>
+
+ <para>
+ Metadata locks acquired during a
+ <literal role="stmt">PREPARE</literal> statement are released
+ once the statement has been prepared, even if preparation occurs
+ within a multiple-statement transaction.
+ </para>
+
+ <para>
+ Before MySQL 6.0.11, when a transaction acquired a metadata lock
+ for a table used within a statement, it released the lock at the
+ end of the statement. This approach had the disadvantage that if
+ a DDL statement occurred for a table that was being used by
+ another session in an active transaction, statements could be
+ written to the binary log in the wrong order.
+ </para>
+
+ </section>
+
+ <section id="external-locking">
+
+ <title>External Locking</title>
+
+ <indexterm>
+ <primary>external locking</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>locking</primary>
+ <secondary>external</secondary>
+ </indexterm>
+
+ <para>
+ External locking is the use of file system locking to manage
+ contention for database tables by multiple processes. External
+ locking is used in situations where a single process such as the
+ MySQL server cannot be assumed to be the only process that
+ requires access to tables. Here are some examples:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ If you run multiple servers that use the same database
+ directory (not recommended), each server must have external
+ locking enabled.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If you use <command>myisamchk</command> to perform table
+ maintenance operations on <literal>MyISAM</literal> tables,
+ you must either ensure that the server is not running, or
+ that the server has external locking enabled so that it
+ locks table files as necessary to coordinate with
+ <command>myisamchk</command> for access to the tables. The
+ same is true for use of <command>myisampack</command> to
+ pack <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ If the server is run with external locking enabled, you can
+ use <command>myisamchk</command> at any time for read
+ operations such a checking tables. In this case, if the
+ server tries to update a table that
+ <command>myisamchk</command> is using, the server will wait
+ for <command>myisamchk</command> to finish before it
+ continues.
+ </para>
+
+ <para>
+ If you use <command>myisamchk</command> for write operations
+ such as repairing or optimizing tables, or if you use
+ <command>myisampack</command> to pack tables, you
+ <emphasis>must</emphasis> always ensure that the
+ <command>mysqld</command> server is not using the table. If
+ you don't stop <command>mysqld</command>, you should at
+ least do a <command>mysqladmin flush-tables</command> before
+ you run <command>myisamchk</command>. Your tables
+ <emphasis>may become corrupted</emphasis> if the server and
+ <command>myisamchk</command> access the tables
+ simultaneously.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ With external locking in effect, each process that requires
+ access to a table acquires a file system lock for the table
+ files before proceeding to access the table. If all necessary
+ locks cannot be acquired, the process is blocked from accessing
+ the table until the locks can be obtained (after the process
+ that currently holds the locks releases them).
+ </para>
+
+ <para>
+ External locking affects server performance because the server
+ must sometimes wait for other processes before it can access
+ tables.
+ </para>
+
+ <para>
+ External locking is unnecessary if you run a single server to
+ access a given data directory (which is the usual case) and if
+ no other programs such as <command>myisamchk</command> need to
+ modify tables while the server is running. If you only
+ <emphasis>read</emphasis> tables with other programs, external
+ locking is not required, although <command>myisamchk</command>
+ might report warnings if the server changes tables while
+ <command>myisamchk</command> is reading them.
+ </para>
+
+ <para>
+ With external locking disabled, to use
+ <command>myisamchk</command>, you must either stop the server
+ while <command>myisamchk</command> executes or else lock and
+ flush the tables before running <command>myisamchk</command>.
+ (See <xref linkend="system-optimization"/>.) To avoid this
+ requirement, use the <literal role="stmt">CHECK TABLE</literal>
+ and <literal role="stmt">REPAIR TABLE</literal> statements to
+ check and repair <literal>MyISAM</literal> tables.
+ </para>
+
+ <para>
+ For <command>mysqld</command>, external locking is controlled by
+ the value of the
+ <literal role="sysvar">skip_external_locking</literal> system
+ variable. When this variable is enabled, external locking is
+ disabled, and vice versa. From MySQL 4.0 on, external locking is
+ disabled by default. Before MySQL 4.0, external locking is
+ enabled by default on Linux or when MySQL is configured to use
+ MIT-pthreads.
+ </para>
+
+ <para>
+ Use of external locking can be controlled at server startup by
+ using the <option role="mysqld">--external-locking</option> or
+ <option role="mysqld">--skip-external-locking</option> option.
+ </para>
+
+ <para>
+ If you do use external locking option to enable updates to
+ <literal>MyISAM</literal> tables from many MySQL processes, you
+ must ensure that the following conditions are satisfied:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ You should not use the query cache for queries that use
+ tables that are updated by another process.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ You should not start the server with the
+ <option role="mysqld">--delay-key-write=ALL</option> option
+ or use the <literal>DELAY_KEY_WRITE=1</literal> table option
+ for any shared tables. Otherwise, index corruption can
+ occur.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ <para>
+ The easiest way to satisfy these conditions is to always use
+ <option role="mysqld">--external-locking</option> together with
+ <option role="mysqld">--delay-key-write=OFF</option> and
+ <option role="sysvar">--query-cache-size=0</option>. (This is
+ not done by default because in many setups it is useful to have
+ a mixture of the preceding options.)
+ </para>
+
+ </section>
+
+ </section>
+
+ <section id="optimizing-database-structure">
+
+ <title>Optimizing Database Structure</title>
+
+ <section id="data-size">
+
+ <title>Make Your Data as Small as Possible</title>
+
+ <indexterm>
+ <primary>data</primary>
+ <secondary>size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>reducing</primary>
+ <secondary>data size</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>storage space</primary>
+ <secondary>minimizing</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>tables</primary>
+ <secondary>improving performance</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>performance</primary>
+ <secondary>improving</secondary>
+ </indexterm>
+
+ <para>
+ One of the most basic optimizations is to design your tables to
+ take as little space on the disk as possible. This can result in
+ huge improvements because disk reads are faster, and smaller
+ tables normally require less main memory while their contents
+ are being actively processed during query execution. Indexing
+ also is a lesser resource burden if done on smaller columns.
+ </para>
+
+ <para>
+ MySQL supports many different storage engines (table types) and
+ row formats. For each table, you can decide which storage and
+ indexing method to use. Choosing the proper table format for
+ your application may give you a big performance gain. See
+ <xref linkend="storage-engines"/>.
+ </para>
+
+ <para>
+ You can get better performance for a table and minimize storage
+ space by using the techniques listed here:
+ </para>
+
+ <itemizedlist>
+
+ <listitem>
+ <para>
+ Use the most efficient (smallest) data types possible. MySQL
+ has many specialized types that save disk space and memory.
+ For example, use the smaller integer types if possible to
+ get smaller tables. <literal role="type">MEDIUMINT</literal>
+ is often a better choice than
+ <literal role="type">INT</literal> because a
+ <literal role="type">MEDIUMINT</literal> column uses 25%
+ less space.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Declare columns to be <literal>NOT NULL</literal> if
+ possible. It makes everything faster and you save one bit
+ per column. If you really need <literal>NULL</literal> in
+ your application, you should definitely use it. Just avoid
+ having it on all columns by default.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ For <literal>MyISAM</literal> tables, if you do not have any
+ variable-length columns
+ (<literal role="type">VARCHAR</literal>,
+ <literal role="type">TEXT</literal>, or
+ <literal role="type">BLOB</literal> columns), a fixed-size
+ row format is used. This is faster but unfortunately may
+ waste some space. See
+ <xref linkend="myisam-table-formats"/>. You can hint that
+ you want to have fixed length rows even if you have
+ <literal role="type">VARCHAR</literal> columns with the
+ <literal role="stmt">CREATE TABLE</literal> option
+ <literal>ROW_FORMAT=FIXED</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ <literal>InnoDB</literal> tables use a compact storage
+ format. In versions of MySQL earlier than 5.0.3,
+ <literal>InnoDB</literal> rows contain some redundant
+ information, such as the number of columns and the length of
+ each column, even for fixed-size columns. By default, tables
+ are created in the compact format
+ (<literal>ROW_FORMAT=COMPACT</literal>). If you wish to
+ downgrade to older versions of MySQL, you can request the
+ old format with <literal>ROW_FORMAT=REDUNDANT</literal>.
+ </para>
+
+ <para>
+ The presence of the compact row format decreases row storage
+ space by about 20% at the cost of increasing CPU use for
+ some operations. If your workload is a typical one that is
+ limited by cache hit rates and disk speed it is likely to be
+ faster. If it is a rare case that is limited by CPU speed,
+ it might be slower.
+ </para>
+
+ <para>
+ The compact <literal>InnoDB</literal> format also changes
+ how <literal role="type">CHAR</literal> columns containing
+ UTF-8 data are stored. With
+ <literal>ROW_FORMAT=REDUNDANT</literal>, a UTF-8
+ <literal>CHAR(<replaceable>N</replaceable>)</literal>
+ occupies 3 × <replaceable>N</replaceable> bytes, given
+ that the maximum length of a UTF-8 encoded character is
+ three bytes. Many languages can be written primarily using
+ single-byte UTF-8 characters, so a fixed storage length
+ often wastes space. With
+ <literal>ROW_FORMAT=COMPACT</literal> format,
+ <literal>InnoDB</literal> allocates a variable amount of
+ storage in the range from <replaceable>N</replaceable> to 3
+ × <replaceable>N</replaceable> bytes for these columns
+ by stripping trailing spaces if necessary. The minimum
+ storage length is kept as <replaceable>N</replaceable> bytes
+ to facilitate in-place updates in typical cases.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ The primary index of a table should be as short as possible.
+ This makes identification of each row easy and efficient.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Create only the indexes that you really need. Indexes are
+ good for retrieval but bad when you need to store data
+ quickly. If you access a table mostly by searching on a
+ combination of columns, create an index on them. The first
+ part of the index should be the column most used. If you
+ <emphasis>always</emphasis> use many columns when selecting
+ from the table, the first column in the index should be the
+ one with the most duplicates to obtain better compression of
+ the index.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ If it is very likely that a string column has a unique
+ prefix on the first number of characters, it is better to
+ index only this prefix, using MySQL's support for creating
+ an index on the leftmost part of the column (see
+ <xref linkend="create-index"/>). Shorter indexes are faster,
+ not only because they require less disk space, but because
+ they also give you more hits in the index cache, and thus
+ fewer disk seeks. See <xref linkend="server-parameters"/>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ In some circumstances, it can be beneficial to split into
+ two a table that is scanned very often. This is especially
+ true if it is a dynamic-format table and it is possible to
+ use a smaller static format table that can be used to find
+ the relevant rows when scanning the table.
+ </para>
+ </listitem>
+
+ </itemizedlist>
+
+ </section>
+
<section id="table-cache">
<title>How MySQL Opens and Closes Tables</title>
Modified: trunk/refman-6.0/sql-syntax-data-definition.xml
===================================================================
--- trunk/refman-6.0/sql-syntax-data-definition.xml 2010-07-14 15:11:37 UTC (rev 21727)
+++ trunk/refman-6.0/sql-syntax-data-definition.xml 2010-07-14 15:35:58 UTC (rev 21728)
Changed blocks: 1, Lines Added: 1, Lines Deleted: 1; 663 bytes
@@ -4876,7 +4876,7 @@
<literal role="type">VARBINARY</literal>, and
<literal role="type">BLOB</literal> columns. Indexing only a
prefix of column values like this can make the index file much
- smaller. See <xref linkend="indexes"/>.
+ smaller. See <xref linkend="column-indexes"/>.
</para>
<indexterm>
| Thread |
|---|
| • svn commit - mysqldoc@docsrva: r21728 - in trunk: . refman-4.1 refman-5.0 refman-5.1 refman-5.5 refman-6.0 | paul.dubois | 14 Jul |