【入門】MySQLテーブルロックの基本|種類と使い方
はじめに:なぜテーブルロックが必要なのか?
データベースは、複数のユーザーやアプリケーションが同時にアクセスし、データの読み書きを行うことが一般的です。このような「同時実行性」は、データベースの効率性を高める上で非常に重要です。しかし、同時アクセスが何の制約もなく行われると、データの整合性が損なわれたり、予期しない結果が生じたりする可能性があります。
例えば、ある銀行口座から別の口座へ送金する処理を考えてみましょう。口座Aから1000円引き出し、口座Bに1000円入金するという一連の操作が必要です。
もし、この処理の途中で、他の処理が口座Aの残高を読み取ったり、更新したりしたらどうなるでしょうか?
送金処理が「口座Aから1000円引き出す」を実行し、まだ「口座Bに1000円入金する」を実行していない間に、別の処理が口座Aの残高を読み取ったとします。この時、口座Aの残高は実際には引き出された後の値であるべきですが、まだ引き出し前の古い値が読み取られてしまうかもしれません。これは「ダーティリード」と呼ばれる問題の一例です。
また、複数の送金処理が同時に同じ口座にアクセスした場合、最終的な残高が計算通りにならない「更新ロスト」のような問題が発生する可能性もあります。
このような同時実行による問題を解決し、データの整合性を保証するために、データベースは「ロック」という仕組みを使用します。ロックは、特定のデータやオブジェクト(テーブル、行など)に対して、他のユーザーからのアクセスを一時的に制限する排他制御のメカニズムです。
MySQLには、様々なレベルのロック機構があります。代表的なものとしては、特定のレコード(行)に対する「行ロック」や、テーブル全体に対する「テーブルロック」などがあります。また、テーブルのスキーマ(構造)に関する変更を管理するための「メタデータロック(MDL)」なども存在します。
この記事では、MySQLのロック機構の中でも基本となる「テーブルロック」に焦点を当て、その種類、使い方、そして注意点について、初心者の方にも分かりやすく詳細に解説していきます。
テーブルロックとは何か?
テーブルロックは、その名の通り、データベースの「テーブル全体」に対してかけられるロックです。このロックを取得すると、指定したテーブルに対する他のセッションからの特定の操作が制限されます。
テーブルロックの主な目的は以下の通りです。
- データの整合性維持: あるセッションがテーブル全体に渡る一括処理(大量のINSERT, UPDATE, DELETEや、複雑な集計など)を行う際に、その処理中に他のセッションからテーブルの内容が変更されるのを防ぎ、処理の一貫性を保証します。
- 競合の制御: 複数のセッションが同じテーブルにアクセスしようとした際に、ロックによってアクセス順序を調整し、意図しない結果やデッドロックなどを回避します(ただし、テーブルロックはデッドロックのリスクも持ちます)。
- スキーマ変更時の安定化: 特にMyISAMのような非トランザクショナルなストレージエンジンにおいて、テーブル構造を変更するようなDDL(Data Definition Language)を実行する前に、テーブルを静止させるために使用されることがあります。
テーブルロックは、MySQLサーバーレベルで実装されています。これは、InnoDBやMyISAMといったストレージエンジンが提供するロック機構(例えばInnoDBの行ロック)とは異なるレイヤーで機能することを意味します。かつてMySQLのデフォルトストレージエンジンがMyISAMだった時代には、MyISAMが行ロックを持たないため、テーブルロックが同時実行制御の中心的な役割を担っていました。現在主流のInnoDBは強力な行ロック機能を持っていますが、テーブルロックはDDL操作の制御や、非トランザクショナルエンジンとの互換性などの理由から、今でも重要なロック機構の一つです。
テーブルロックは、ユーザーがSQLステートメント(主に LOCK TABLES
)を使って「手動で」取得するものと、特定の操作(例えばDDL)によってMySQLが「自動的に」取得するものがあります。この記事で主に解説するのは、ユーザーが LOCK TABLES
を使って明示的に取得するテーブルロックです。
MySQLのテーブルロックの種類
ユーザーが LOCK TABLES
ステートメントを使って明示的に取得できるテーブルロックには、いくつかのモード(種類)があります。これらのモードは、他のセッションからのアクセスをどの程度制限するかによって異なります。
主なテーブルロックのモードは以下の4つです。
READ
ロック (共有ロック)WRITE
ロック (排他ロック)READ LOCAL
ロックLOW_PRIORITY_WRITE
ロック
これらのロックは、ロックを取得したセッション と 他のセッション の、それぞれに対するテーブルへのアクセス許可/制限が異なります。
1. READ
ロック (共有ロック)
READ
ロックは「共有ロック」とも呼ばれます。これは、複数のセッションが同時に同じテーブルに対して READ
ロックを取得できるためです。読み取り操作はデータの変更を伴わないため、同時に複数のセッションが読み取ってもデータの整合性は損なわれません。
-
特徴:
- ロックを取得したセッションは、ロックを取得したテーブルからのデータ読み取り(
SELECT
)のみ可能です。データの変更(INSERT
,UPDATE
,DELETE
,TRUNCATE TABLE
,DROP TABLE
など)はできません。 - 他のセッションは、ロックを取得したテーブルからのデータ読み取り(
SELECT
)は可能です。 - 他のセッションからのデータの変更(
INSERT
,UPDATE
,DELETE
,TRUNCATE TABLE
,DROP TABLE
など)は、ロックが解放されるまで待機させられます。
- ロックを取得したセッションは、ロックを取得したテーブルからのデータ読み取り(
-
挙動のイメージ:
- セッションAがテーブルTに対して
READ
ロックを取得しました。 - セッションAは、テーブルTに対して
SELECT
はできますが、UPDATE
やDELETE
はできません。 - セッションBは、テーブルTに対して
SELECT
はできます。 - セッションCは、テーブルTに対して
UPDATE
を実行しようとすると、セッションAがREAD
ロックを解放するまで待たされます。
- セッションAがテーブルTに対して
-
取得方法:
sql
LOCK TABLES table_name READ;
複数のテーブルに同時にロックをかけることも可能です。
sql
LOCK TABLES table1 READ, table2 READ; -
解放方法:
LOCK TABLES
で取得したロックは、以下のいずれかの方法で解放されます。UNLOCK TABLES
ステートメントを実行する。- 別の
LOCK TABLES
ステートメントを実行する(新しいロックが古いロックを置き換えます)。 - ロックを取得したセッションが終了する。
- ロックを取得したセッションが、トランザクション開始 (
START TRANSACTION
/BEGIN
) 後にCOMMIT
またはROLLBACK
を実行する(注意: トランザクション内でLOCK TABLES
を使う場合の特殊な挙動です。後述します)。 - ロックを取得したセッションが、一部のDDLステートメント(例えば
ALTER TABLE
)を実行する。
-
具体的な使用例/シナリオ:
- テーブル全体のダンプ: MyISAMのようなテーブルロックしか持たないエンジンで、テーブル全体の整合性を保ったまま
SELECT * INTO OUTFILE
やmysqldump
でデータを取得したい場合。取得中に他のセッションからの更新が入ると、取得データに不整合が生じる可能性があるため、READ
ロックをかけて読み取りのみ可能にする。 - 一貫性のあるレポート作成: 複数のテーブルから複雑な結合処理を行い、一貫性のあるスナップショットデータに基づいてレポートを作成したい場合。関連するテーブルに
READ
ロックをかけることで、レポート作成中にデータが変更されるのを防ぎます。ただし、InnoDBであればトランザクション分離レベル(特にREPEATABLE READ
やSERIALIZABLE
)で同等の、あるいはより粒度の細かい制御が可能です。
- テーブル全体のダンプ: MyISAMのようなテーブルロックしか持たないエンジンで、テーブル全体の整合性を保ったまま
-
注意点、副作用:
READ
ロック中でも他のセッションは読み取りが可能なので、読み取りに関しては高い並列性を保てます。- しかし、ロックを保持している間は、他のセッションからの書き込み処理が全て待機させられます。これは、特に書き込み頻度が高いテーブルでは、他のセッションの応答性能を大きく低下させる可能性があります。
- ロックを取得したセッション自身も、ロックを取得したテーブルへの書き込みができなくなります。
2. WRITE
ロック (排他ロック)
WRITE
ロックは「排他ロック」とも呼ばれます。これは、一度に一つのセッションしか特定のテーブルに対して WRITE
ロックを取得できないためです。また、WRITE
ロックを取得したセッションのみがそのテーブルへの読み書きを行え、他のセッションからの読み書きは全て制限されます。
-
特徴:
- ロックを取得したセッションは、ロックを取得したテーブルへの読み取り(
SELECT
)と変更(INSERT
,UPDATE
,DELETE
など)が可能です。 - 他のセッションは、ロックが解放されるまで、ロックを取得したテーブルへの一切のアクセス(読み取り、書き込み問わず)が待機させられます。
- ロックを取得したセッションは、ロックを取得したテーブルへの読み取り(
-
挙動のイメージ:
- セッションAがテーブルTに対して
WRITE
ロックを取得しました。 - セッションAは、テーブルTに対して
SELECT
、UPDATE
、DELETE
など、全ての操作ができます。 - セッションBは、テーブルTに対して
SELECT
を実行しようとすると、セッションAがWRITE
ロックを解放するまで待たされます。 - セッションCは、テーブルTに対して
INSERT
を実行しようとすると、セッションAがWRITE
ロックを解放するまで待たされます。
- セッションAがテーブルTに対して
-
取得方法:
sql
LOCK TABLES table_name WRITE;
複数のテーブルに同時にロックをかけることも可能です。
sql
LOCK TABLES table1 WRITE, table2 WRITE; -
解放方法:
READ
ロックと同様です(UNLOCK TABLES
、セッション終了、新しいLOCK TABLES
、トランザクション終了(特殊ケース)、DDL実行など)。 -
具体的な使用例/シナリオ:
- テーブル全体の一括更新/削除: MyISAMテーブル全体に対して、データの不整合を完全に防ぎつつ、大量のレコードを更新したり削除したりする場合。他のセッションからのアクセスを完全に遮断することで、操作中のデータ変更による問題を回避します。
- MyISAMテーブルの最適化/修復: MyISAMテーブルの
OPTIMIZE TABLE
やCHECK TABLE
,REPAIR TABLE
といったメンテナンス操作を実行する際に、通常は内部的にWRITE
ロックが必要になります。手動で事前にロックを取得しておくことで、操作のタイミングを制御したり、他のセッションへの影響を最小限にしたりする場合があります(ただし、これらのコマンドは通常自動で適切なロックを取得します)。 - DDL実行前のテーブル静止: MyISAMなど、DDL実行中にテーブルがロックされるエンジンで、特定のタイミングでテーブルの構造変更(
ALTER TABLE
)を行いたい場合。事前に手動でWRITE
ロックを取得しておき、他のアクセスを停止させてからDDLを実行することで、予期しない競合を防ぎます。
-
注意点、副作用:
WRITE
ロックは非常に強力なロックであり、ロックを保持している間は、ロック対象テーブルへの全てのセッションからのアクセスを停止させます。- これは、システムの並列性を極端に低下させ、ボトルネックとなる可能性が非常に高いです。
- ロックを取得するセッション自身は自由に読み書きできますが、他のセッションは完全に待たされるため、ロックの保持時間は最小限にする必要があります。
3. READ LOCAL
ロック
READ LOCAL
ロックは READ
ロックに似ていますが、特定の条件下での同時書き込みを許可する点が異なります。主にMyISAMテーブルの Concurrent Insert
機能と組み合わせて使用されます。
-
特徴:
- ロックを取得したセッションは、ロックを取得したテーブルからのデータ読み取り(
SELECT
)のみ可能です(READ
ロックと同様)。 - 他のセッションは、ロックを取得したテーブルからのデータ読み取り(
SELECT
)は可能です(READ
ロックと同様)。 - 他のセッションは、ロックが解放されるまで、データの変更(
UPDATE
,DELETE
,TRUNCATE TABLE
,DROP TABLE
など)は待機させられます(READ
ロックと同様)。 - ただし、MyISAMテーブルでは、他のセッションからの
INSERT
ステートメントは、テーブルの末尾に追加する場合に限り、ロックを取得したセッションが読み取り中でも実行できます。 これが「Concurrent Insert(同時挿入)」と呼ばれる機能です。
- ロックを取得したセッションは、ロックを取得したテーブルからのデータ読み取り(
-
挙動のイメージ (MyISAM + Concurrent Insert):
- セッションAがMyISAMテーブルTに対して
READ LOCAL
ロックを取得しました。 - セッションAは、テーブルTに対して
SELECT
を実行中です。 - セッションBは、テーブルTに対して
INSERT
を実行します。テーブルに空きブロックがない場合、このINSERT
はテーブルの末尾に追加されます。この時、セッションAのSELECT
が実行中でも、セッションBのINSERT
はブロックされずに実行されます。 - セッションCは、テーブルTに対して
UPDATE
を実行しようとすると、セッションAがREAD LOCAL
ロックを解放するまで待たされます。
- セッションAがMyISAMテーブルTに対して
-
取得方法:
sql
LOCK TABLES table_name READ LOCAL; -
解放方法:
READ
ロック、WRITE
ロックと同様です。 -
使用シナリオ:
- MyISAMテーブルに対する読み取りと挿入の並列性向上: MyISAMテーブルに対して、比較的長時間の読み取り処理(レポート作成など)を実行しつつ、同時に新しいデータの挿入も受け付けたい場合に使用します。
-
注意点、副作用:
READ LOCAL
は、主にMyISAMストレージエンジンの Concurrent Insert 機能のために存在します。InnoDBではこの機能は意味を持ちません(InnoDBは行ロックベースであり、テーブルロック中であっても、競合しない行への挿入は通常ブロックされません)。- Concurrent Insert が可能なのは、空きブロックがなく、テーブルの末尾にデータを追加する場合に限られます。テーブル内に削除などでできた空きブロックがある場合は、
INSERT
もブロックされます。 UPDATE
やDELETE
はREAD LOCAL
ロック中でもブロックされるため、書き込み操作全般の並列性を向上させるわけではありません。
4. LOW_PRIORITY_WRITE
ロック
LOW_PRIORITY_WRITE
ロックは WRITE
ロックに似ていますが、ロック取得の優先順位が低いという特徴があります。これは、既に待機している READ
ロック要求がある場合、そちらを優先してから LOW_PRIORITY_WRITE
ロックを取得するという挙動を取るためです。
-
特徴:
- ロックを取得したセッションは、ロックを取得したテーブルへの読み取り(
SELECT
)と変更(INSERT
,UPDATE
,DELETE
など)が可能です(WRITE
ロックと同様)。 - 他のセッションからのアクセス制限も
WRITE
ロックと同様ですが、ロック取得時の挙動が異なります。 - ロック取得の優先順位が低い:
LOCK TABLES ... LOW_PRIORITY_WRITE
ステートメントが実行された際、もし対象テーブルに対して既に待機しているREAD
ロック要求(他のセッションがLOCK TABLES ... READ
を実行し、テーブルが他のロックでブロックされているなど)がある場合、MySQLはまずそれらのREAD
ロックを取得させます。待機中のREAD
ロック要求が全て処理された後、LOW_PRIORITY_WRITE
ロックが取得されます。これにより、書き込みよりも読み取り要求を優先させることができます。
- ロックを取得したセッションは、ロックを取得したテーブルへの読み取り(
-
挙動のイメージ:
- セッションAがテーブルTに対して
LOW_PRIORITY_WRITE
ロックを要求しました。 - その時、セッションBが既にテーブルTに対して
READ
ロックの取得を待機しています。 - MySQLはまずセッションBに
READ
ロックを取得させ、その後のSELECT
などを実行させます。 - セッションAは、セッションBの
READ
ロックが解放されるのを待ちます。 - セッションCが新たにテーブルTに対して
SELECT
を実行しようとした場合、これはセッションBのREAD
ロック中なので実行可能です。 - セッションAは、セッションBを含む、他の全てのセッションがテーブルTへのアクセスを終了し、ロックが全て解放されるのを待ちます。
- 全ての待機中の
READ
ロック要求が処理され、テーブルがフリーになった後、セッションAがLOW_PRIORITY_WRITE
ロックを取得します。 - セッションAが
LOW_PRIORITY_WRITE
ロックを取得している間は、他のセッションからのテーブルTへのアクセスは全て待機させられます(WRITE
ロック中と同様)。
- セッションAがテーブルTに対して
-
取得方法:
sql
LOCK TABLES table_name LOW_PRIORITY_WRITE; -
解放方法:
READ
ロック、WRITE
ロックと同様です。 -
使用シナリオ:
- 重要でない一括書き込み処理: 頻繁に発生する読み取り操作のパフォーマンスを犠牲にすることなく、たまに実行される重要度の低い一括書き込み処理を行いたい場合。例えば、ログテーブルに対する古いデータの定期的なアーカイブや削除など、即時性が求められない処理に利用できます。
-
注意点、副作用:
- ロック取得の優先順位が低いだけで、ロック取得後の挙動は
WRITE
ロックと同じく他のセッションを完全にブロックします。ロック保持時間は最小限にする必要があります。 - 待機中の
READ
ロック要求が多い場合、LOW_PRIORITY_WRITE
ロックは長時間待たされる可能性があります。場合によっては飢餓状態(Starvation)に陥る可能性もゼロではありません。 - このロックは、あくまでロック取得時の優先順位を制御するものです。既に
WRITE
ロック(あるいはLOW_PRIORITY_WRITE
ロック)が取得されている場合は、他の全てのロック要求と同様に待機します。
- ロック取得の優先順位が低いだけで、ロック取得後の挙動は
LOCK TABLES
ステートメントの詳細
LOCK TABLES
ステートメントは、一つまたは複数のテーブルに対して、指定したモードのロックを同時に取得するために使用します。
構文
基本的な構文は以下の通りです。
sql
LOCK TABLES
tbl_name [[AS] alias] mode
[, tbl_name [[AS] alias] mode] ...
tbl_name
: ロックを取得したいテーブル名。alias
: テーブルにエイリアス(別名)を付けてロックする場合に指定します。例えば、自己結合などで同じテーブルを複数回参照する場合に必要です。mode
: 取得したいロックのモード (READ
,[READ] LOCAL
,WRITE
,LOW_PRIORITY_WRITE
) を指定します。READ LOCAL
のREAD
は省略可能です (LOCAL
とだけ書くこともできます)。
例:
mytable
テーブルにREAD
ロックを取得:
sql
LOCK TABLES mytable READ;table1
にWRITE
ロック、table2
にREAD
ロックを同時に取得:
sql
LOCK TABLES table1 WRITE, table2 READ;orders
テーブルにWRITE
ロックを取得し、エイリアスo
を使用:
sql
LOCK TABLES orders AS o WRITE;
(注意: エイリアスを使ってロックを取得した場合、そのセッションでは、ロックが解放されるまで、エイリアス名 (o
) を使ってのみテーブルにアクセスできます。元のテーブル名 (orders
) ではアクセスできなくなります。)
ロック取得の挙動 (アトミック性)
LOCK TABLES
ステートメントは、指定された全てのテーブルに対するロックを、アトミックに 取得しようとします。つまり、指定した全てのロックを取得できるか、あるいは一つも取得できないかのどちらかです。部分的にロックが取得されることはありません。
もし、指定したテーブルのどれか一つでも、他のセッションが既に保持している互換性のないロックによってロック取得がブロックされる場合、LOCK TABLES
ステートメント全体が待機します。全てのロックが取得可能になるまで、ステートメントは完了しません。
ロックを取得する順序は、ステートメントで指定された順序に依存しません。MySQLは内部的にデッドロックを回避するために、テーブル名をアルファベット順にソートしてロックを取得しようとします。これは、複数のセッションが同じテーブルセットに対して LOCK TABLES
を実行する際に発生する可能性のあるデッドロックを減らすための重要な仕組みです。
ロック解除の挙動
LOCK TABLES
で手動で取得したロックは、以下のいずれかの状況で解除されます。
UNLOCK TABLES
ステートメントの実行: 明示的にロックを解除するコマンドです。ロックを取得したセッションがこのコマンドを実行すると、そのセッションが保持している全てのテーブルロックが解除されます。
sql
UNLOCK TABLES;- セッションの終了: ロックを取得したセッションが切断されるか、終了すると、そのセッションが保持している全てのテーブルロックは自動的に解除されます。
- 別の
LOCK TABLES
ステートメントの実行: ロックを取得したセッションが、続けて別のLOCK TABLES
ステートメントを実行した場合、古いロックセットは解除され、新しいロックセットが取得されます。 - DDL ステートメントの実行: ロックを取得したセッションが、ロック対象のテーブルに対する
ALTER TABLE
,DROP TABLE
,RENAME TABLE
,TRUNCATE TABLE
といった一部のDDLステートメントを実行した場合、通常、そのセッションが保持している全てのテーブルロックは自動的に解除されます。これは、DDL操作自体が排他的なメタデータロックを必要とし、手動で取得したテーブルロックと共存できないためです。 - トランザクションの終了 (
COMMIT
/ROLLBACK
) とautocommit
設定: この点は少し複雑です。autocommit
がON
の場合(デフォルト)、各ステートメントが自動的にコミットされます。この設定ではLOCK TABLES
の効果はステートメント単位ではなく、次のUNLOCK TABLES
が実行されるか、セッションが終了するまで持続します。autocommit
がOFF
の場合、またはSTART TRANSACTION
/BEGIN
で明示的にトランザクションを開始した場合、トランザクションがCOMMIT
またはROLLBACK
で終了すると、そのセッションが保持している全てのテーブルロックが自動的に解除されます。 つまり、トランザクションの中でLOCK TABLES
を取得し、トランザクションを終えるとロックも解放される、という挙動になります。
LOCK TABLES
とトランザクションの関係性
InnoDBのようなトランザクショナルなストレージエンジンを使用している場合、LOCK TABLES
を使う際にはトランザクションとの関係を理解することが重要です。
LOCK TABLES
はトランザクションを暗黙的に開始する? (古い情報): 過去のMySQLのバージョン(特に5.5以前やMyISAMがデフォルトだった時代)では、LOCK TABLES
が実行されると、たとえautocommit=ON
であっても、暗黙的にトランザクションが開始されるかのように説明されることがありました。しかし、MySQLの新しいバージョン(5.6以降、特にInnoDBがデフォルトになってから)では、LOCK TABLES
自体がトランザクションを開始するわけではありません。ロックを取得するだけで、トランザクションの状態(コミット可能かどうか)は別途管理されます。- トランザクション中での
LOCK TABLES
:START TRANSACTION
/BEGIN
でトランザクションを開始した後にLOCK TABLES
を実行することは可能です。この場合、ロックはトランザクションが終了する (COMMIT
またはROLLBACK
) まで保持されます。トランザクションが終了すると、前述のようにロックも自動的に解除されます。これは、一つのアトミックな処理単位(トランザクション)内でテーブル全体を静止させたい場合に利用できる挙動です。 LOCK TABLES
後でのトランザクション開始:autocommit=ON
の状態でLOCK TABLES
を実行し、その後START TRANSACTION
を実行した場合、トランザクションが開始されますが、既に取得されているテーブルロックはそのまま保持されます。そして、このトランザクションがCOMMIT
またはROLLBACK
で終了すると、そのトランザクション中に変更されたデータはコミット/ロールバックされますが、LOCK TABLES
で取得したロックは解除されません。 ロックはUNLOCK TABLES
かセッション終了まで持続します。これは、autocommit=ON
の状態でのLOCK TABLES
は、トランザクションのスコープとは独立して機能する傾向があるためです。- 推奨される使い方: InnoDBを使用している場合、通常は行ロックと適切なトランザクション分離レベルで十分なケースが多いです。どうしてもテーブルロックが必要な場合は、
autocommit=OFF
に設定するか、あるいはSTART TRANSACTION
で明示的にトランザクションを開始してからLOCK TABLES
を実行し、トランザクション終了時にロックも自動的に解放される挙動を利用するのが、意図が明確になりやすいかもしれません。ただし、InnoDBでLOCK TABLES
を長時間保持することは、他のセッションの並列性を著しく損なうため、可能な限り避けるべきです。
メタデータロック (MDL) とテーブルロックの違い、関係性
LOCK TABLES
で取得するテーブルロックとは別に、MySQLには「メタデータロック(MDL: Metadata Lock)」という重要なロック機構があります。これはMySQL 5.5で導入され、DDL(テーブル構造の変更)とDML(データの読み書き)が同時に実行されることによる問題を解決することを目的としています。
-
MDLの目的:
- セッションAがテーブルの構造を変更する
ALTER TABLE
を実行中に、セッションBが同じテーブルにSELECT
やUPDATE
を実行しようとした場合、MDLはセッションBのDML操作をブロックします。これにより、DDL操作中にテーブル構造が不安定な状態であるにもかかわらず、DMLが実行されてしまうことを防ぎ、データの整合性やサーバーの安定性を保ちます。 - セッションAがDML操作を実行中に、セッションBがそのテーブルの
DROP TABLE
を実行しようとした場合、MDLはセッションBのDDL操作をブロックします。これにより、DML操作中にテーブルが削除されることを防ぎます。
- セッションAがテーブルの構造を変更する
-
MDLの取得:
- MDLはユーザーが明示的に
LOCK METADATA
のようなステートメントで取得するものではありません(そのようなステートメントは存在しません)。 - MDLは、MySQLサーバーが自動的に取得・解放します。
- DMLステートメント(
SELECT
,INSERT
,UPDATE
,DELETE
など)が実行される際、対象テーブルに対して短い期間のMDLが取得されます。 - DDLステートメント(
ALTER TABLE
,DROP TABLE
,RENAME TABLE
,TRUNCATE TABLE
など)が実行される際、対象テーブルに対して排他的なMDLが比較的長い期間取得されます。
- MDLはユーザーが明示的に
-
テーブルロック (
LOCK TABLES
) とMDLの関係性:LOCK TABLES
ステートメントを実行してテーブルロックを取得すると、MySQLはロック対象のテーブルに対して、手動で取得したテーブルロックが解放されるまでの間、対応するMDLを保持します。- 例えば、
LOCK TABLES mytable READ;
を実行すると、mytable
に対してREAD
ロックが取得されるだけでなく、MDLシステムによってmytable
に対する共有MDLが取得され、UNLOCK TABLES
が実行されるまで保持されます。 - 同様に、
LOCK TABLES mytable WRITE;
を実行すると、mytable
に対してWRITE
ロックが取得されるだけでなく、MDLシステムによってmytable
に対する排他MDLが取得され、UNLOCK TABLES
が実行されるまで保持されます。 - これは重要な点です。
LOCK TABLES
を長時間保持すると、それに伴ってMDLも長時間保持されることになります。特にWRITE
ロックに伴う排他MDLは、他のセッションからのDMLはもちろん、同じテーブルに対するDDL操作をもブロックします。 もし他のセッションが同じテーブルに対してDDLを実行しようとして待機している場合、そのDDLは他のセッションからのDMLもブロックするため、MDLの待機はシステム全体に大きな影響を与える可能性があります。 - 逆に、あるテーブルに対するMDLが(例えば他のセッションの長いDDLによって)既に取得され、待機中のMDL要求がある場合、そのテーブルに対する
LOCK TABLES
もブロックされる可能性があります。
つまり、LOCK TABLES
は、データへのアクセスを制御する従来のテーブルロックと、DDLとDMLの競合を防ぐためのMDLの両方の側面に関わるロック機構であると言えます。現代のMySQLにおいては、特にInnoDBを使う場合、LOCK TABLES
の主な影響は「対応するMDLを長時間保持してしまうことによる、他のセッションからのDMLやDDLへの影響」であることが多いです。
テーブルロックの使用例とシナリオ
前述のロックの種類ごとの使用例をまとめ、より具体的なシナリオをいくつか紹介します。
シナリオ1:MyISAMテーブルに対する一貫性のあるバックアップ/ダンプ
- 問題: MyISAMテーブルは行ロックを持たないため、
mysqldump
やSELECT ... INTO OUTFILE
でデータを取得している最中にテーブルが更新されると、取得データに不整合が生じる可能性があります。 -
解決策: ダンプを開始する前に、対象のMyISAMテーブルに対して
READ
ロックを取得します。
“`sql
— ダンプ対象のテーブルが他にもあれば全て指定する
LOCK TABLES myisam_table1 READ, myisam_table2 READ;— mysqldump コマンドや SELECT … INTO OUTFILE を実行
— 例: SELECT * INTO OUTFILE ‘/tmp/data.csv’ FROM myisam_table1;— ダンプが完了したらロックを解放
UNLOCK TABLES;
``
mysqldump –single-transaction
* **効果:** ロック中に他のセッションからの更新はブロックされますが、読み取りは許可されるため、ダンプ処理と他のセッションからの読み取りを両立できます。ただし、ロック中は更新が完全に停止するため、更新頻度が高いテーブルでは他の業務への影響が大きくなります。
* **InnoDBの場合:** InnoDBであれば、通常オプションを使用します。これはトランザクション分離レベル(特に
REPEATABLE READ`)を利用して、ダンプ開始時点のスナップショットを一貫性をもって取得するため、テーブルロックは不要です。これが、現代のシステムでInnoDBが主流である理由の一つです。
シナリオ2:MyISAMテーブルに対する一括更新/削除
- 問題: MyISAMテーブル全体に渡る大量の更新や削除を行う際に、その操作中に他のセッションがテーブルにアクセスすると、意図しない結果やエラーが生じる可能性があります。
-
解決策: 更新/削除を開始する前に、対象のMyISAMテーブルに対して
WRITE
ロックを取得します。
“`sql
LOCK TABLES myisam_large_table WRITE;— 大量のUPDATEやDELETEステートメントを実行
— 例: DELETE FROM myisam_large_table WHERE old_date < CURDATE() – INTERVAL 1 YEAR;— 処理が完了したらロックを解放
UNLOCK TABLES;
``
WRITE` ロック中は、他のセッションからのテーブルへのアクセスが完全に遮断されます。これにより、更新/削除処理は他の干渉を受けることなく安全に実行できます。
* **効果:**
* 注意点: ロック中はテーブルへのアクセスが完全に停止するため、システム全体への影響が非常に大きいです。可能な限り処理を高速に行い、ロック保持時間を短くする必要があります。また、InnoDBであれば、大量の更新/削除であっても行ロックが使用されるため、通常はテーブル全体をロックする必要はありません。バッチ処理として小さく区切ったり、パーティショニングを利用したりすることで、オンライン処理への影響を最小限に抑えることができます。
シナリオ3:MyISAMテーブルの ALTER TABLE
実行前の静止
- 問題: MyISAMテーブルに対する
ALTER TABLE
は、テーブルを再構築するため時間がかかる場合があります。この処理中にDML操作が行われると、エラーやデータ破損のリスクがあります(MDLによってある程度は防がれますが、手動で完全に制御したい場合)。 -
解決策:
ALTER TABLE
を実行する前に、対象のMyISAMテーブルに対してWRITE
ロックを取得し、他のアクセスを完全に停止させます。
“`sql
LOCK TABLES myisam_table WRITE;— ALTER TABLE ステートメントを実行
— 例: ALTER TABLE myisam_table ADD COLUMN new_column INT;— ALTER TABLE が完了したらロックを解放
UNLOCK TABLES;
``
WRITE
* **効果:**ロックにより他のセッションからのアクセスを完全に停止させ、安全な状態で
ALTER TABLEを実行できます。
ALTER TABLE
* **InnoDBの場合:** InnoDBのは、多くの場合、オンラインで実行可能なアルゴリズム(
ALGORITHM=INSTANT,
INPLACE)を提供します。これらのアルゴリズムは、DDL実行中もDML操作をブロックする時間を最小限に抑えるか、あるいは全くブロックしません。そのため、InnoDBで
ALTER TABLEのために手動でテーブルロックを取得する必要はほとんどありません。もし
COPY` アルゴリズムが必要な場合でも、適切なMDLが自動的に取得・管理されます。
シナリオ4:読み取り中にMyISAMへの挿入を許可 (READ LOCAL
)
- 問題: MyISAMテーブルに対して長時間のレポート作成などの読み取り処理を実行中に、新しいデータの挿入も受け付けたい。
-
解決策: 対象のMyISAMテーブルに対して
READ LOCAL
ロックを取得します。
“`sql
LOCK TABLES myisam_log_table READ LOCAL;— 長時間の SELECT ステートメントを実行
— 例: SELECT COUNT(*) FROM myisam_log_table WHERE log_date >= ‘…’ GROUP BY user_id;— 読み取りが完了したらロックを解放
UNLOCK TABLES;
``
READ LOCAL
* **効果:**ロック中は他のセッションからの
UPDATEや
DELETEはブロックされますが、Concurrent Insert が可能な条件(テーブル末尾への挿入)を満たす
INSERTステートメントはブロックされずに実行されます。これにより、読み取りと挿入の並列性を部分的に実現できます。
UPDATE
* **注意点:** あくまでMyISAMのConcurrent Insert機能に依存します。InnoDBではこの機能は適用されません。また、や
DELETE、テーブル内の空きブロックを利用する
INSERT` はブロックされます。
シナリオ5:書き込みを待機中の読み取りより低優先にする (LOW_PRIORITY_WRITE
)
- 問題: たまに実行する大量データのインポートやバッチ更新処理が、頻繁に発生する読み取りクエリの応答性能を阻害しないようにしたい。
-
解決策: 対象テーブルに対する書き込み処理を行う前に
LOW_PRIORITY_WRITE
ロックを取得します。
“`sql
LOCK TABLES my_table LOW_PRIORITY_WRITE;— 大量データINSERT/UPDATE/DELETEなどの書き込み処理を実行
— 例: LOAD DATA INFILE … INTO TABLE my_table;— 書き込み処理が完了したらロックを解放
UNLOCK TABLES;
``
LOW_PRIORITY_WRITE
* **効果:**ロックの取得要求は、既に待機している
READロック要求よりも優先順位が低くなります。これにより、ロック取得までの間、待機中の読み取り処理が先に実行される機会を得られます。ロック取得後は
WRITEロックと同様に他のアクセスをブロックします。
WRITE
* **注意点:** ロック取得までの優先順位を調整するだけであり、ロック保持中の挙動はロックと同じく他のアクセスを完全にブロックします。また、
LOW_PRIORITY_WRITEロック自身が待機中の間も、他の新たな
READ` ロック要求が先に取得される可能性があります。
これらのシナリオから分かるように、LOCK TABLES
は主にMyISAMのようなテーブルロックしか持たないエンジンや、特定のメンテナンス操作(DDLを含む)の際にテーブル全体を静止させたい場合に有効です。現代のMySQLで主流のInnoDBでは、強力な行ロック機能とトランザクションが提供されるため、LOCK TABLES
を使用する場面は限定的であり、むしろパフォーマンス上のボトルネックとなるリスクが高いことに注意が必要です。
テーブルロックの監視とトラブルシューティング
LOCK TABLES
や自動で取得されるMDLによってテーブルがロックされ、他のセッションが待機している状況は、システムの応答性能に直結する問題です。このようなロックの状態を監視し、問題発生時に原因を特定するためのツールがMySQLにはいくつか用意されています。
1. SHOW OPEN TABLES
このステートメントは、現在MySQLサーバーで開かれている(使用中の)テーブルに関する情報の一部を表示します。テーブルロックに関する情報も含まれています。
sql
SHOW OPEN TABLES WHERE In_use > 0 OR Name_locked > 0;
Table
: テーブル名。Database
: データベース名。In_use
: そのテーブルを使用しているアクティブなスレッド(セッション)の数。これは必ずしもロックを意味しませんが、高い値は競合を示唆します。Name_locked
: テーブルの名前(メタデータ)がロックされているかどうかを示すフラグ(1: ロックされている、0: ロックされていない)。これはMDLの状態を反映します。LOCK TABLES
ステートメントによるテーブルロックは、このName_locked
を1に設定します。
このコマンドで In_use
や Name_locked
が高い値を示している場合、そのテーブルで何らかのロックが発生している可能性が高いと判断できます。
2. SHOW PROCESSLIST
/ performance_schema.threads
SHOW PROCESSLIST
は現在実行中のクエリやアイドル状態のセッション一覧を表示します。performance_schema.threads
テーブルはより詳細な情報を提供します。ここで、ロック待ちの状態を確認できます。
sql
SHOW PROCESSLIST;
または
sql
SELECT id, user, host, db, command, time, state, info
FROM performance_schema.threads
WHERE processlist_state IS NOT NULL;
ロック待ち状態にあるセッションは、State
カラムに以下のような表示が出ることがあります。
Waiting for table metadata lock
: メタデータロック(MDL)の取得を待機しています。これは、他のセッションが同じテーブルに対して互換性のないMDL(例えば、手動のLOCK TABLES
や、実行中のDDL)を保持している場合に発生します。LOCK TABLES ... WRITE
によるロック待ちは通常この状態として表示されます。Waiting for global read lock
:FLUSH TABLES WITH READ LOCK
といったグローバルリードロックの取得を待機しています。これはテーブルロックとは少し異なりますが、全てのテーブルをロックするため関連性があります。Waiting for table level lock
: より古いバージョンや特定の状況で、テーブルロックそのものの取得を待機していることを示す場合があります。
State
がロック待ちになっているセッションの Info
カラムを確認すると、どのクエリがロック待ちになっているのか特定できます。さらに、SHOW PROCESSLIST
の出力や performance_schema.threads
の parent_thread_id
などから、どのセッションがロックを保持しているのかを特定できる場合があります。
3. performance_schema.data_locks
および performance_schema.metadata_locks
performance_schema
データベースには、MySQLサーバー内部の様々なイベントや状態が記録されており、ロックに関する非常に詳細な情報も含まれています。
-
performance_schema.metadata_locks
: 現在アクティブなMDLや、MDLの待機状態に関する情報を提供します。
sql
SELECT
OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, SOURCE, OWNER_THREAD_ID, OWNER_EVENT_ID
FROM performance_schema.metadata_locks;OBJECT_TYPE
,OBJECT_SCHEMA
,OBJECT_NAME
: ロック対象のオブジェクト(TABLE, SCHEMAなど)。LOCK_TYPE
: ロックの種類(SHARED_READ, SHARED_WRITE, EXCLUSIVEなど)。LOCK TABLES ... READ
は SHARED_READ MDL、LOCK TABLES ... WRITE
は EXCLUSIVE MDL に対応することが多いです。LOCK_DURATION
: ロックの期間(STATEMENT, TRANSACTION, EXPLICITなど)。LOCK TABLES
によるロックはEXPLICIT
と表示されます。LOCK_STATUS
: ロックの状態(GRANTED: 取得済み, PENDING: 待機中)。PENDING
の行は、他のセッションがロック待ちになっていることを示します。OWNER_THREAD_ID
: ロックを取得または待機しているスレッドのID(performance_schema.threads
のthread_id
に対応)。
このテーブルを調べると、どのテーブルに対して、どのセッションが、どのようなMDLを保持しており(
GRANTED
)、そのために他のどのセッションが、どのようなMDLの取得を待機しているか(PENDING
)を詳細に把握できます。LOCK TABLES
によるテーブルロックが原因で発生しているMDLの問題は、ここでLOCK_DURATION = 'EXPLICIT'
のロックを確認することで特定できます。 -
performance_schema.data_locks
: InnoDBの行ロックに関する情報を提供しますが、テーブルロックに関する情報も一部含まれる場合があります。ただし、LOCK TABLES
によるロック起因の待機は、通常はMDLとして扱われるため、metadata_locks
を確認する方が一般的です。
ロック待ちの原因特定と対処
SHOW PROCESSLIST
やperformance_schema.threads
でState
がロック待ちのセッションを見つける。- そのセッションの
Info
カラムで待機しているクエリを確認する。 performance_schema.metadata_locks
でLOCK_STATUS = 'PENDING'
となっている行を探し、待機しているオブジェクト(テーブル)と、待機中のMDLの種類を確認する。OWNER_THREAD_ID
から、どのセッションが待機しているかも分かる。performance_schema.metadata_locks
で、上記のPENDING
ロックと競合している、同じオブジェクトに対するLOCK_STATUS = 'GRANTED'
のロックを探す。GRANTED
ロックを保持しているOWNER_THREAD_ID
を特定し、そのセッションが実行しているクエリ(SHOW PROCESSLIST
やperformance_schema.threads
でid
を使う)や、ロックを取得した経緯(手動のLOCK TABLES
なのか、自動のMDLなのか)を調査する。特にLOCK_DURATION = 'EXPLICIT'
であれば、それは手動でLOCK TABLES
が実行された結果保持されているMDLです。- 原因となっているセッションやクエリが特定できたら、状況に応じて以下の対処を検討します。
- 原因となっているクエリが正当なものであれば、その完了を待つ。
- 原因となっているセッションがアイドル状態になっているにも関わらずロックを保持している場合(例えば、
LOCK TABLES
を実行したままUNLOCK TABLES
を忘れた、あるいはエラーで処理が中断したなど)、そのセッションをKILL
する。 - 原因となっているクエリが意図せず長時間ロックを保持してしまっている場合、そのクエリの実行を中断させる(
KILL QUERY
またはKILL CONNECTION
)。 - そもそも設計上の問題で頻繁にロック競合が発生している場合、処理の見直しやInnoDBへの移行、より細かいロック粒度の利用などを検討する。
テーブルロックやMDLによるロック待ちは、システムの可用性や性能に深刻な影響を与えるため、これらの監視方法を理解しておくことは非常に重要です。
テーブルロックの注意点とベストプラクティス
テーブルロックは強力な排他制御手段ですが、その粒度の粗さゆえに、特に並列性が求められる現代のデータベースシステムでは慎重に使用する必要があります。
1. パフォーマンスへの影響
テーブルロックはテーブル全体を対象とするため、ロック保持中は他のセッションからのアクセスを大きく制限します。WRITE
ロックは読み書き問わず全てのアクセスをブロックし、READ
ロックや READ LOCAL
ロックも書き込みをブロックします。ロックを保持する時間が長ければ長いほど、他のセッションは長時間待機することになり、システム全体のスループットが著しく低下します。これは、ウェブアプリケーションのように多数の同時リクエストを捌く必要があるシステムでは致命的な問題となり得ます。
2. ロックを保持する時間の最小化
テーブルロックを使用する必要がある場合でも、ロックを取得している時間は可能な限り短くすることが最も重要です。ロック中に実行する処理は、高速に完了するように最適化する必要があります。不要になったらすぐに UNLOCK TABLES
を実行することを忘れないでください。
3. トランザクショナルエンジン (InnoDB) と非トランザクショナルエンジン (MyISAM) での使い分け
- InnoDB: 現在のMySQLのデフォルトであり、最も広く使用されているストレージエンジンです。InnoDBは行ロック機能を持ち、トランザクションをサポートします。ほとんどのDML操作(
SELECT
,INSERT
,UPDATE
,DELETE
)は行ロックを使用するため、同じテーブルに対して複数のセッションが同時に異なる行を操作できます。これにより高い並列性が実現されます。InnoDBにおいては、通常のDML操作のためにLOCK TABLES
を手動で使用することはほとんどありません。LOCK TABLES
は主に、DDL操作(特に古いタイプのALTER TABLE
など)、または特定の非常に特殊なシナリオでテーブル全体を完全に静止させたい場合に検討されますが、その場合でもMDLの保持による影響を十分に理解し、慎重に判断する必要があります。多くの場合、行ロック、トランザクション分離レベル、あるいはアプリケーション側での排他制御で代替可能です。 - MyISAM: 行ロックを持たず、同時アクセス制御は専らテーブルロックに依存します。そのため、古いシステムや特定の用途(例えば、頻繁な更新がなく、参照が主体のテーブル、あるいは全文検索など)ではまだ使用されていますが、現代の多くの用途には向きません。MyISAMにおいては、同時書き込み制御や一貫性のある読み取りのために
LOCK TABLES
が必要になる場面が多いです。 しかし、MyISAM自体が現代のワークロードには向かない場合が多いです。
4. ほとんどの場合、InnoDBでは行ロックやトランザクション分離レベルで十分
InnoDBを使用している場合、ほとんどの同時実行性に関する問題は、行ロック、トランザクション(START TRANSACTION
, COMMIT
, ROLLBACK
)、およびトランザクション分離レベル(REPEATABLE READ
, READ COMMITTED
など)を適切に使用することで解決できます。これらの機構はテーブルロックよりも粒度が細かく、必要なデータだけをロックするため、高い並列性を維持できます。テーブルロックは、行ロックでは実現できない「テーブル全体の一貫した状態」をある期間保証したい場合に限定的に検討されるべきです。
5. LOCK TABLES
を避けるべきケース
- 高い並列性が求められるオンラインシステム: ウェブサイトのバックエンドやAPIなど、多数の同時リクエストを処理するシステムでは、テーブルロックはボトルネックの大きな原因となります。
- 長時間の処理: ロック中に時間がかかる処理を実行することは、システム全体を停止させることに等しいです。可能な限り、処理を分割したり、ロックが不要な方法(例えば、一時テーブルの使用や、影響範囲の小さい行ロックの使用)を検討したりすべきです。
- デッドロックのリスク: 複数のテーブルに対して異なる順序で
WRITE
ロックを取得しようとする複数のセッションが存在する場合、デッドロックが発生する可能性があります(例:セッションAがテーブルT1のWRITEロックを取得後T2のWRITEロックを待機、セッションBがT2のWRITEロックを取得後T1のWRITEロックを待機)。MySQLは内部的にテーブル名のアルファベット順にロックを取得しようとするなどのデッドロック回避策を講じますが、複雑なシナリオではデッドロックが発生し得ます。
6. DDLとMDLの関係性を理解する重要性
InnoDBにおいては、手動の LOCK TABLES
が自動のMDLとどのように連携し、他のセッションからのDDLやDMLにどのような影響を与えるかを理解しておくことが重要です。特に LOCK TABLES ... WRITE
は排他MDLを保持するため、他のセッションからの ALTER TABLE
などもブロックし、MDL待機による広範な影響を引き起こす可能性があります。
7. 自動ロック(MDLなど)と手動ロック(LOCK TABLES
)の使い分け
MySQLは内部的に多くのロックを自動で管理しています(例:InnoDBの行ロック、MDL)。これらの自動ロックは通常効率的に管理され、必要な期間だけ保持されます。一方、LOCK TABLES
はユーザーが明示的に取得・解放する必要があり、その管理責任はユーザー側にあります。不用意な LOCK TABLES
は、MySQLの自動的なロック管理機構の効率を損ない、問題を引き起こす可能性があります。特別な理由がない限り、InnoDBの自動ロック機構に任せるのがベストプラクティスです。
テーブルロックと他のロック機構
MySQLにはテーブルロック以外にも様々なロック機構が存在します。テーブルロックの位置づけを理解するために、それらとの違いを簡単に見ていきましょう。
- 行ロック (Row-Level Lock): InnoDBストレージエンジンが提供する最も細かい粒度のロックです。テーブル内の特定の行や行の範囲をロックします。これにより、異なるセッションが同じテーブルの異なる行に同時にアクセスすることが可能になり、高い並列性を実現できます。ほとんどのDML操作は行ロックを使用します。テーブルロックとは異なり、ユーザーがSQLで直接的に行ロックを取得することは少なく(
SELECT ... FOR UPDATE
やSELECT ... LOCK IN SHARE MODE
は例外)、トランザクションとDMLステートメントの実行に基づいてMySQLが自動的に管理します。 - ページロック (Page-Level Lock): BDBストレージエンジン(MySQL 5.1で廃止)などが使用していたロック粒度です。テーブルを一定サイズのページに分割し、ページ単位でロックを取得します。テーブルロックよりは粒度が細かいですが、行ロックよりは粗いです。現代のMySQLではあまり関係ありません。
- メタデータロック (MDL): 前述の通り、DDLとDMLの競合を防ぐために、MySQLサーバーレベルで自動的に取得・管理されるロックです。テーブルのメタデータ(スキーマ、定義)に対するアクセスを制御します。
LOCK TABLES
はこれに対応するMDLを長時間保持させる効果があります。 - ネーミングロック (Naming Lock):
GET_LOCK()
関数やRELEASE_LOCK()
関数を使って、ユーザーが任意の文字列名に対して取得できるグローバルな(MySQLサーバー全体で有効な)ロックです。データベース内の特定のオブジェクトではなく、アプリケーション固有のリソースに対する排他制御などに利用できます。テーブルとは直接関係ありません。 - グローバルロック: MySQLサーバー全体、あるいは全てのデータベースに対するロックです。例えば
FLUSH TABLES WITH READ LOCK
は、全てのテーブルに対するグローバルな読み取りロックを取得し、その後の書き込み操作を全てブロックします。主にバックアップ用途などで使用されます。
テーブルロックは、これらのロック機構の中で「テーブル全体」を対象とするロックとして位置づけられます。現代のMySQL(特にInnoDB)では、通常は行ロックが主流であり、テーブルロックは特定のシナリオやMyISAMエンジンの互換性のために存在する、やや特殊なロック機構と言えます。
まとめ
この記事では、MySQLのテーブルロックについて、その基本的な考え方、種類、使い方、監視方法、そして注意点までを詳細に解説しました。
- テーブルロックは、テーブル全体に対して排他的または共有的にロックをかけることで、同時アクセスによるデータの整合性問題を解決する手段の一つです。
- 主な種類として、読み取りを許可し書き込みをブロックする
READ
ロック、読み書き全てをブロックする強力なWRITE
ロック、そして特殊なケースで同時挿入を許可するREAD LOCAL
、読み取り要求を優先するLOW_PRIORITY_WRITE
があります。 LOCK TABLES
ステートメントを使って手動で取得し、UNLOCK TABLES
やセッション終了、トランザクション終了(特殊ケース)などで解放します。LOCK TABLES
は、テーブルロックだけでなく、対応するメタデータロック(MDL)も保持するため、特にInnoDB環境ではMDLによる他のセッション(特にDDL)への影響を考慮する必要があります。- テーブルロックは粒度が粗いため、高い並列性を損ないやすいという欠点があります。ロック保持時間は最小限に抑えるべきです。
- 現代のMySQLで主流のInnoDBは強力な行ロックとトランザクションを提供するため、ほとんどの場合、テーブルロックは不要であり、安易な使用は避けるべきです。テーブルロックは主にMyISAMテーブルの管理や、特定の限られたシナリオでのみ有効です。
- ロック待ちの問題が発生した場合は、
SHOW OPEN TABLES
,SHOW PROCESSLIST
, そしてperformance_schema.metadata_locks
などのツールを使って原因を特定し、適切に対処する必要があります。
テーブルロックはMySQLの歴史の中で重要な役割を果たしてきましたが、ストレージエンジンの進化(特にInnoDBの普及)により、その使用頻度や推奨される場面は大きく変化しました。テーブルロックが必要となるのはどのような場合か、そしてどのようなリスクがあるのかを正しく理解し、状況に応じてInnoDBの行ロックやトランザクションなどのより細かい粒度のロック機構を活用することが、高パフォーマンスで安定したデータベースシステムを構築する上で非常に重要です。
入門者の方は、まずInnoDBの行ロックとトランザクションによる並列性制御を理解することから始め、テーブルロックについては、主に非トランザクショナルエンジンとの互換性や特殊なメンテナンス操作で必要となるケースがある、という位置づけで学ぶのが良いでしょう。
この情報が、MySQLのテーブルロックを理解し、適切に使用するための助けとなれば幸いです。