MySQL データベースは、3 つの Web アプリケーションにストレージ バックエンド サービスを提供します。ただし、最近、「テーブルメタデータロックを待機しています」というエラーが永続的に発生しました。これはほぼ常に発生しますが、理由がわかりません。
リーリーもちろん、対応するプロセスを強制終了することもできます。ただし、データベース「bookmaker3」のテーブル構造を作成しようとしているプログラムを再起動すると、新しく作成されたプロセスが再び Metallock になります。
データベースを削除することさえできません:
リーリーこれにより金属製のロックも生成されます。
この問題を解決するにはどうすればよいですか?
P粉6474494442023-10-19 00:15:30
残念ながら、受け入れられている解決策は間違っています。それは完全に正しいです
これは確かに (ほぼ 確かに、以下を参照) やるべきことです。しかし、その後、
が表示されます。...そして 1398 は ロックとの接続ではありません。どうして? 1398 は、ロックを待機している接続です。これは、まだロックを取得していないことを意味するため、強制終了しても効果はありません。ロックを保持しているプロセスは引き続きロックを保持し続けるため、 何らかの操作を実行しようとしている次の スレッドも 停止し、適切な順序で「メタデータ ロックの待機」に入ります。 < /p> 「メタデータ ロックを待機している」プロセス (WFML) が同様にブロックしないことを保証することはできませんが、WFML プロセスを強制終了するだけでは
何も起こらないことは確かです。 本当の理由は、
別のプロセスがロックを保持しているためです、そしてさらに重要なことに、SHOW FULL PROCESSLIST はどのプロセス
を直接教えてくれないのです。
確実に言えることは、
存在しないということです。この人たちは被害者だと言えるでしょう。
SHOW FULL PROCESSLIST WILL
プロセスが 何かを実行しているかどうかを示します (はい)。通常は機能します。ここで、ロックを保持しているプロセス は何もせず 、同様に何もせず「スリープ中」として報告する他のスレッドに隠されています。
SHOW FULL PROCESSLIST で DML を実行しているプロセス、または「データ送信」状態にあるプロセスが表示された場合は、
がほぼ確実に原因です。他のプロセスは、ロックが解放されるのを待っています (暗黙的なロックである可能性があります。プロセスは LOCK TABLE を発行する必要はまったくなく、実際には別の方法でロックされます)。ただし、プロセスは操作を実行していないときにロックを保持し、「スリープ中」として適切にマークされることがあります。
OP の場合、犯人 はほぼ確実に プロセス
です。このプロセスはプロセス 1398 より前に開始されており、現在 スリープ 状態にあり、 46秒続きました。 1396 は明らかにやるべきことをすべて実行したため (MySQL に関する限り、現在スリープ状態であることが判明し、46 秒間スリープ状態が続いています)、# で に入ったスレッドはありません。 ## ロックを保持し、スリープ前も保持することができます (そうでないと 1396 も停止します)。
MySQL の「デッドロックフリー」ロック ポリシーにより、どのプロセスもロックを保持したり、ロックを解放したり、再びロックを復元したりすることはできません。そのため、ロック待機は常に、ロックをまだ保持している、または一度も保持したことがないプロセスによって実行されます。以前のロックはプロセスによって引き起こされました。これは、ロック「キュー」が に順序付けされていることを保証するため、便利です (以下でこの事実を利用します)。
重要
SHOW FULL PROCESSLIST では、すべてのプロセスが 表示されません。したがって、ロックは目に見えないプロセスによって保持されている可能性があります。
つまり: SHOW FULL PROCESSLIST ですべてが表示され、Running
プロセスが表示される場合は、おそらくそのプロセスが責任を負っており、そのプロセスが実行中の処理を完了するまで待つ必要があります。または、あなたはそれを殺すことができます - 自己責任で)。
この回答の残りの部分では、プロセスが明白な理由
プロセスリストの表示
上記は、SLEEP 状態のプロセスのみを表示するように調整でき、とにかく時間の降順に並べ替えるので、ハングしたプロセス (通常は「待機中」の順序により になります) を見つけやすくなります。メタデータの場合、「ロックの直前に 1 回スリープします」; は常に保留中のスリープ時間よりも 多いスリープの 1 つです。
###大事なこと###
手っ取り早く汚い解決策、あまりお勧めできませんが、手っ取り早いです
同じデータベース上の「スリープ」状態にあり、「メタデータ ロックを待機中」状態にある最も古いプロセスを強制終了します。 アルノー・アマウリーならこうする: WaitingForMetadataLock に少なくとも 1 つのスレッドがあるデータベースごとに:
このデータベース上の WFML の最も古い接続は Z 秒間存在しています
100 回中 99 回、強制終了されるスレッドは、スリープ状態にあり、メタデータ ロックを待っている古いスレッド より集中的な修理 SHOW ENGINE INNODB STATUS を実行し、「TRANSACTION」セクションを確認します。特に、
のようなものが見つかります。 リーリー次に、
SHOW FULL PROCESSLISTはあなたが殺さなければならないスレッドです。これらの変更は失われます。
MySQL で何もしないことは、一般的に何もしないことを意味するわけではないことに注意してください。 MySQL からいくつかのレコードを取得し、FTP アップロード用の CSV を構築する場合、FTP アップロード中、MySQL 接続はアイドル状態になります。
実際には、MySQL を使用するプロセスと MySQL サーバーが同じコンピュータ上にあり、そのコンピュータで Linux が実行されており、root 権限を持っている場合、どの プロセス
が要求されたファイルを所有しているかを確認する方法があります。ロックを接続します。これにより、プロセスが 本当に 何かを実行しているかどうか (CPU 使用率、最悪の場合は
に基づいて) を判断できるようになり、強制終了しても安全かどうかを判断するのに役立ちます。誰か。
「永続的」または「プールされた」MySQL 接続を使用する Web アプリケーションでこの問題が発生するのを確認しましたが、通常は時間の節約はほとんどありません。Web アプリケーションのインスタンスは終了しますが、 接続は終了しません。したがって、生きたままロックされており、他の人からブロックされています。
私が見つけたもう 1 つの興味深いアプローチ は、上記の仮説で、いくつかの行 を返すクエリを実行し、その一部のみを取得するというものです 。クエリが「自動クリーン」に設定されていない場合 (ただし、基礎となる DBA が設定している場合)、接続は開いたままになり、テーブルの完全なロックが防止されます。行を選択し、エラーがあるか(存在しない)どうか(存在する必要がある)を確認することで行が存在することを確認するコードでこれに遭遇しましたが、は実際には取得されませんでした行 .< /em>
PHP と PDO開くときに、オプションを設定します (4 番目のオプションは new PDO()):
リーリー
切断時:リーリー
データベースに問い合わせるですが、あまり新しくない 、これは非推奨になる予定です 、原因を見つけるもう 1 つの方法は次のとおりです (ここでも権限情報モードが必要になります)。 リーリー 実際の解決策には時間と労力がかかります
Web アプリケーションが終了するか、Web アプリケーションの軽量スレッド インスタンスが終了すると、
コンテナー/接続プールは存在しない可能性があります。接続を開いたままにするのは container であるため、明らかに接続は閉じられていません。予想どおり、MySQL は操作 が完了したとはみなしません。 Web アプリケーション自体がクリーンアップしない場合 (トランザクションの
ROLLBACK または COMMIT
がない、UNLOCK TABLES
がないなど)、Web アプリケーションはアプリケーションは実行を開始します 任意の操作 はまだ存在します
ため、他の操作は引き続きブロックされる可能性があります。
その場合、解決策は 2 つあります。さらに悪いことに、
があります。しかし、クエリ間の待ち時間が長すぎるとどうなるか考えてみてください (文字通り、「MySQL サーバーがなくなった」)。利用可能な場合は、mysql_ping を使用できます (まもなく非推奨になります。 PDO には回避策 があります。 あるいは、 エラーが発生したかどうか を確認することもできます。この問題が発生した場合は、接続を再度開きます(これが Python の方法です。) したがって、パフォーマンスのコストはわずかですが、これは実行可能です。 より優れた、よりスマートなソリューションの実装はそれほど簡単ではありません。すべての行を取得するかすべてのクエリ リソースを解放することを確認し、すべての例外をキャッチして正しく処理するか、可能であれば 永続的な接続を完全にスキップして、スクリプト自体をクリーンアップできるようにしてください。各インスタンスが独自の接続を作成するか、
スマート プール ドライバーを使用します (PHP PDO では、明示的に false に設定された PDO::ATTR_PERSISTENT を使用します)。
代わりに (PHP のように)、トランザクションをコミットまたはロールバックすることでデストラクターと例外ハンドラーに接続を強制的にクリーンアップさせることもできます (これで十分です)。あるいは、明示的なテーブルのロック解除と RELEASE_ALL_LOCKS( )、または良好な結果を得るには、接続自殺 (KILL CONNECTION_ID()
) を送信します。
既存の結果セット リソースをクエリして解放する方法がわかりません。唯一の方法は、これらのリソースをプライベート配列に保存することです。