MySQL UPDATEとSELECTを1つのパスで
実行するタスクのMySQLテーブルがあり、各行には単一のタスクのパラメーターがあります。
ループ内でタスクを実行する多くのワーカーアプリ(おそらく異なるマシン上)があります。
アプリは、MySQLのネイティブC APIを使用してデータベースにアクセスします。
タスクを所有するために、アプリはそのようなことをします:
グローバルに一意のIDを生成します(簡単にするために、数値であるとしましょう)
UPDATE tasks
SET guid = %d
WHERE guid = 0 LIMIT 1
SELECT params
FROM tasks
WHERE guid = %d
最後のクエリが行を返す場合、その行を所有し、実行するパラメーターがあります
サーバーへの1回の呼び出しで同じ効果(つまり、行を「所有」し、そのパラメーターを取得する)を実現する方法はありますか?
このようにしてみてください
UPDATE `lastid` SET `idnum` = (SELECT `id` FROM `history` ORDER BY `id` DESC LIMIT 1);
上記のコードは私のために働きました
これを行うプロシージャを作成できます。
CREATE PROCEDURE prc_get_task (in_guid BINARY(16), OUT out_params VARCHAR(200))
BEGIN
DECLARE task_id INT;
SELECT id, out_params
INTO task_id, out_params
FROM tasks
WHERE guid = 0
LIMIT 1
FOR UPDATE;
UPDATE task
SET guid = in_guid
WHERE id = task_id;
END;
BEGIN TRANSACTION;
CALL prc_get_task(@guid, @params);
COMMIT;
まったく同じ問題があります。代わりにPostreSQLを使用してしまいました UPDATE ... RETURNING
:
オプションのRETURNING句を使用すると、UPDATEは実際に更新された各行に基づいて値を計算して返します。テーブルの列、および/またはFROMで言及された他のテーブルの列を使用する式はすべて計算できます。テーブルの列の新しい(更新後)値が使用されます。 RETURNINGリストの構文は、SELECTの出力リストの構文と同じです。
例:UPDATE 'my_table' SET 'status' = 1 WHERE 'status' = 0 LIMIT 1 RETURNING *;
または、あなたの場合:UPDATE 'tasks' SET 'guid' = %d WHERE 'guid' = 0 LIMIT 1 RETURNING 'params';
申し訳ありませんが、これでMySQLの質問に答えられないことはわかっています。PostgreSQLに切り替えるのは簡単ではないかもしれませんが、これは、私たちがそれを行うために見つけた最良の方法です。 6年後も、MySQLはUPDATE ... RETURNING
をサポートしていません。これは将来のある時点で追加される可能性がありますが、現時点では MariaDBはDELETEステートメントでのみ使用できます 。
単一のクエリを探している場合、それは起こり得ません。 UPDATE関数は、具体的には更新されたアイテムの数のみを返します。同様に、SELECT関数はテーブルを変更せず、戻り値のみを変更します。
プロシージャを使用すると、実際にはプロシージャが1つの関数に変換され、ロックが問題になる場合に便利です。最大の懸念がネットワークトラフィックである場合(つまり、渡されるクエリが多すぎる場合)、この手順を使用します。サーバーの過負荷が懸念される場合(つまり、DBの負荷が大きすぎる)、プロシージャの余分なオーバーヘッドによって状況が悪化する可能性があります。
単一の呼び出し部分についてはわかりませんが、説明しているのはロックです。ロックはリレーショナルデータベースの重要な要素です。
行をロックして読み取り、MySQLで更新する詳細はわかりませんが、 mysql lock documentation を少し読むだけで、あらゆる種類のロックベースの操作を実行できます。
locks のpostgres文書には、テーブルのロック、テーブルの読み取り、テーブルの変更など、実行する操作を正確に説明する優れた例があります。
UPDATE tasks
SET guid = %d, params = @params := params
WHERE guid = 0 LIMIT 1;
値が効果的に変更されたかどうかに応じて、1または0を返します。
SELECT @params AS params;
これは、接続から変数を選択するだけです。
差出人: ここ