転送元:http://ctripmysqldba.iteye.com/blog/1938150(変更あり)
テーブルの変更などのDDL操作を実行する場合、MySQLにはテーブルメタデータロックを待機する待機シーンがある場合があります。さらに、alter table TableAの操作がWaiting for table metadata lockの状態でスタックすると、TableAの後続の操作(読み取りを含む)は実行できなくなります。これらの操作は、Tables Openingの段階でWaiting for tableメタデータロックロックにも入るためです。キューを待っています。このようなロック待機キューが本番環境のコアテーブルに表示されると、悲惨な結果を招きます。
テーブルを変更してWaiting for tableメタデータロックを生成する理由は、実際には非常に単純であり、一般的には次の単純なシナリオです。
シナリオ1:実行に時間がかかり、DDLがブロックされてから、同じテーブルの後続のすべての操作がブロックされる
show processlistを使用すると、TableAで進行中の操作(読み取りを含む)があることがわかります。このとき、alter tableステートメントはメタデータの排他ロックを取得できず、待機します。
これは最も基本的な状況であり、mysql 5.6のオンラインddlと競合しません。変更テーブルの操作中(下図を参照)、メタデータの排他ロックは作成後のステップで取得されます。変更テーブルプロセス(通常、最も時間がかかるステップ)に進むと、テーブルの読み取りと書き込みは正常に行われます。続行するには、これはオンラインddlのパフォーマンスであり、以前のようにテーブル変更プロセス全体での書き込みをブロックしません。(もちろん、すべてのタイプの変更操作をオンラインにすることができるわけではありません。詳細については、公式マニュアルを参照してください:http : //dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html)
解決策: DDLが配置されているセッションを強制終了します。
シナリオ2:コミットされていないもの、DDLのブロック、および同じテーブルの後続のすべての操作のブロック
show processlistを介してTableAの操作を確認できませんが、実際にはコミットされていないトランザクションがあり、information_schema.innodb_trxで確認できます 。トランザクションが完了する前に、TableAのロックは解放されず、変更テーブルはメタデータの排他ロックも取得できません。
解決策:information_schema.innodb_trx \ G から*を選択し 、コミットされていないもののsidを見つけて強制終了し、ロールバックさせます。
シーン3:
show processlistを介してTableAの操作を確認できず、information_schema.innodb_trxに進行中のトランザクションがありません。これはおそらく、明示的なトランザクションで、失敗した操作がTableAで実行されたためです(たとえば、存在しないフィールドが照会されました)。このとき、トランザクションは開始されませんでしたが、失敗したステートメントによって取得されたロックはまだ有効であり、解放されていません。 。失敗したステートメントは、performance_schema.events_statements_currentテーブルから見つけることができます。
公式マニュアルの記載は以下の通りです。
構文的には有効であるが実行中に失敗したステートメントのメタデータロックをサーバーが取得した場合、サーバーはロックを早期に解放しません。失敗したステートメントはバイナリログに書き込まれ、ロックはログの一貫性を保護するため、ロックの解放はトランザクションの最後まで延期されます。
つまり、構文エラーを除いて、他のエラーステートメントによって取得されたロックは、トランザクションがコミットまたはロールバックされるまで解放されません。失敗したステートメントはバイナリログに書き込まれ、ロックはログの一貫性を保護しますが、この動作の理由を理解することは困難です。これは、間違ったステートメントがバイナリログにまったく記録されないためです。
処理方法:performance_schema.events_statements_currentを使用してsid を見つけ、セッションを強制終了します。DDLが配置されているセッションを強制終了することもできます。
つまり、変更テーブルのステートメントは非常に危険です(実際、彼の危険は実際にはコミットされていないものまたは長いトランザクションによって引き起こされます)。操作の前に、進行中の操作がないこと、コミットされていないトランザクションがないことを確認することをお勧めします。明示的なトランザクションにはエラーステートメントはありません。alter tableのメンテナンスタスクがある場合、誰も監視していないときに実行します。メタメタロックの長時間の待機を回避するために、lock_wait_timeoutでタイムアウトを設定するのが最善です。