0

私の質問は次 のよう になります。受け入れられた回答で提案されているものに近いロジックをすでに実装していることを除いて、MySQLクエリでロックされた行を無視します。私の質問は、最初にプロセスIDを設定する方法です。すべてのサーバーは次のようなクエリを実行します(コードはRuby on Railsにありますが、結果のmysqlクエリは次のようになります)。

UPDATE (some_table) SET process_id=(some process_id) WHERE (some condition on row_1) AND process_id is null  ORDER BY (row_1) LIMIT 100

ここで何が起こるかというと、すべてのプロセスが同じ行を更新しようとし、ロックされ、ロックを待機してタイムアウトします。ロックされている行をサーバーに無視してもらいたい(ロックが解除された後、process_idはnullではなくなるため、ここでロックする意味がないため)。レコードのバッチをランダム化して更新しようとすることもできますが、問題は、上記のクエリのように、row_1に基づいて更新に優先順位を付けたいことです。だから私の質問は、レコードがロックされているかどうかをチェックし、ロックされている場合は無視する方法はありますか?

4

1 に答える 1

1

いいえ、すでにロックされている行を無視する方法はありません。最善の策は、どの行も長時間ロックしないようにすることです。これにより、ロックの競合の期間が非常に短くなります。これは通常、トランザクション内で行をロックし ( を使用FOR UPDATE)、行を更新して「ロック済み」としてマークすることにより、行を「勧告的」にロックすることを意味します。

たとえば、最初に何もロックせずに候補行を見つけたいとします。

SELECT id FROM t WHERE lock_expires IS NULL AND lock_holder IS NULL <some other conditions>;

必要な行のみを非常に迅速にロックします。

START TRANSACTION;
SELECT * FROM t WHERE id = <id> AND lock_expires IS NULL AND lock_holder IS NULL;
UPDATE t SET lock_expires = <some time>, lock_holder = <me> WHERE id = <id>;
COMMIT;

(技術的な注意: 複数の行をロックする場合は、必ず特定の順序でロックしてください。主キーの昇順を選択することをお勧めします。順不同またはランダムな順序でロックすると、競合するプロセスによってプログラムがデッドロックに陥ります。 .)

これで、他のプロセスをブロックすることなく、行を処理するのに必要なだけ ( 未満lock_expires) かかることができます (非ロック選択中は行と一致しないため、常に無視されます)。行が処理されると、何もブロックすることなく、UPDATEまたはDELETEそれを実行できます。id

于 2013-03-24T17:02:48.867 に答える