4

このタイプの質問は数回投稿されていますが、提供される解決策は次の状況では理想的ではありません。最初のクエリでは、この最初のクエリが実行されたときに存在することがわかっているテーブル名を選択しています。次に、それらをループしながら、選択したテーブル内のレコード数を照会したいのですが、それらがまだ存在する場合のみです。問題は、ループ中に一部のテーブルが別のスクリプトによって削除されることです。例えば ​​:

SELECT tablename FROM table
-- returns say 100 tables

while (%tables){
    SELECT COUNT(*) FROM $table
    -- by the time it gets to the umpteenth table, it's been dropped
    -- so the SELECT COUNT(*) fails
}

そして、cronで実行されているため、致命的に失敗し、cronから失敗したことを示すメールが送信されます。

DBD::mysql::st の実行に失敗しました: テーブル 'xxx' が /usr/local/lib/perl/5.10.1/Mysql.pm 行 175 に存在しません。

スクリプトは非推奨の Mysql.pm perl モジュールを使用しています。

4

2 に答える 2

1

明らかに、クエリを実行する前にテーブルが削除されないように、テーブルを保護する必要があります。ドロップの可能性を回避するために、ある種のテーブル ロックで開始する場合、他の場所から発行された DROP TABLE クエリは何らかのロック エラーで失敗するか、少なくとも SELECT が終了するまで待機することに注意してください。テーブルの削除はあまり頻繁に使用される操作ではないため、ほとんどの場合、サーバーの操作中にスキーマの設計が維持されます。観察されるのは、非常にまれな動作です。一般に、他のクエリ中にテーブルがドロップされないようにすることはサポートされていませんが、以下のドキュメントのコメントで、セマフォ テーブルを使用してそれを達成するためのトリックを見つけることができます。

http://dev.mysql.com/doc/refman/5.1/en/lock-tables.html

「テーブルロックは、他のセッションによる不適切な読み取りまたは書き込みからのみ保護します。ロックを保持しているセッションは、読み取りロックであっても、DROP TABLE などのテーブルレベルの操作を実行できます。切り捨て操作はトランザクションセーフではないため、次の場合にエラーが発生します。セッションは、アクティブなトランザクション中またはテーブル ロックを保持している間に試行します。」

「通常、読み取りロックまたは書き込みロックでサポートされていないテーブルで何かを行う必要があり (テーブルのドロップまたは切り捨てなど)、協力できる場合は、これを試すことができます: セマフォ テーブルを使用し、プロセスごとに 2 つのセッションを作成します。 . 最初のセッションで、必要に応じてセマフォ テーブルの読み取りまたは書き込みロックを取得します。

于 2012-10-16T06:54:24.773 に答える
1

perl コードを eval ブロッ​​クに入れて失敗しないように保護できるはずです。そんな感じ:

eval {
    # try doing something with DBD::mysql
};
if ($@) {
    # oops, mysql code failed.
    # probably need to try it again
}

または、これを「while」ループに入れることもできます

Postgres のようなより優れたサーバーを使用した場合、適切な解決策はすべてをトランザクションに含めることです。しかし、MySQL ではドロップ テーブルはトランザクションによって保護されません。

于 2012-10-16T07:05:37.983 に答える