3

概要

ストアド プロシージャを呼び出すイベントがある場合、一度に実行されるプロシージャのインスタンスが 1 つだけであることを確認するためのベスト プラクティスは何ですか? 具体的には、イベントがティックオーバーするのにかかる時間よりも、プロシージャの実行に時間がかかる場合があります。


次の捏造された例を考えてみましょう。イベントのティックオーバーに1秒かかり、プロシージャの実行に5秒かかります。

手順:

DELIMITER ;;
CREATE PROCEDURE `P_wait`()
BEGIN
    SELECT SLEEP(5);
END;;
DELIMITER ;

イベント:

DROP EVENT IF EXISTS `E_wait`;
DELIMITER ;;
CREATE EVENT `E_wait`
    ON SCHEDULE
        EVERY 1 SECOND
    DO
        BEGIN
            CALL `P_wait`();   //proc_call
        END;;
DELIMITER ;

ご想像のとおり、イベントの実行中は、 に の 5 つのインスタンスが表示SLEEP()されPROCESSLISTます。

mysql> SHOW PROCESSLIST;
+-------+------+-----------+-------+---------+------+-------------+------------------+
| Id    | User | Host      | db    | Command | Time | State       | Info             |
+-------+------+-----------+-------+---------+------+-------------+------------------+
| 27045 | root | localhost | temp  | Query   |    0 | NULL        | SHOW PROCESSLIST |
| 27069 | root | localhost | temp  | Connect |    4 | User sleep  | SELECT SLEEP(5)  |
| 27070 | root | localhost | temp  | Connect |    3 | User sleep  | SELECT SLEEP(5)  |
| 27072 | root | localhost | temp  | Connect |    2 | User sleep  | SELECT SLEEP(5)  |
| 27073 | root | localhost | temp  | Connect |    1 | User sleep  | SELECT SLEEP(5)  |
| 27074 | root | localhost | temp  | Connect |    0 | User sleep  | SELECT SLEEP(5)  |
+-------+------+-----------+-------+---------+------+-------------+------------------+

この例ではそうではありませんが、プロシージャがブロックされていた場合 ( SELECT ... FOR UPDATEStatement を含むトランザクションが含まれている場合など)、これがすぐに問題に発展することがわかります。


質問

E_waitが 1 秒ごとに刻み込まれ、 のインスタンスP_waitがまだ実行されている場合に再度呼び出されないようにする最善の方法は何ですか? P_wait一度に実行するインスタンスは最大でも 1 つだけです。ここでのベストプラクティスは何ですか?

基本的に/*PROCEDURE_NOT_RUNNING*/、イベントを次のように変更した場合、代わりに何を配置する必要があります:

    ...
        BEGIN
            IF /*PROCEDURE_NOT_RUNNING*/ THEN
                CALL wait_test();   //proc_call
            END IF;
        END;;
    ...
  • 手順内からイベントE_waitを変更する (最初に無効にP_waitし、最後に再度有効にする) ことはできません。これは、イベントが無効になっている間にサーバーが再起動すると、イベントがまったく実行されなくなる可能性があるためです。
  • テーブルに値を保存して、それを使用してプロシージャがまだ実行されているかどうかを確認することもできますが、サーバーが正確に間違った時間に実行を停止すると、ロックアップする可能性があるという同じ問題が発生するようです。
  • この議論の全体的なポイントは、手順の実行に任意に長い時間がかかる可能性があるため、イベントスケジュールを 5 秒に変更するだけでは受け入れられないということです:P

望ましい結果

上記のイベントを実行し、最大で 1 つのSELECT SLEEP(5)inのインスタンスのみを表示するにはSHOW PROCESSLIST

4

2 に答える 2

5

この問題に対して、組み込みのロック機能のいくつかを使用することが提案されています。試してみて、問題を解決できたら更新します。

編集:

イベントを変更してロックを含めると、目的の結果が得られました。

DROP EVENT IF EXISTS `E_wait`;
DELIMITER ;;
CREATE EVENT `E_wait`
    ON SCHEDULE
        EVERY 1 SECOND
    DO
        BEGIN

            SELECT GET_LOCK('temp.E_wait', 0) INTO @got_lock;
            IF @got_lock = 1 THEN

                CALL `P_wait`();

                SELECT RELEASE_LOCK('temp.E_wait') INTO @discard;
            END IF;

        END;;
DELIMITER ;

このスタックオーバーフローの質問への回答が役に立ちました。

于 2013-10-08T21:32:38.523 に答える