web-dev-qa-db-ja.com

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回の呼び出しで同じ効果(つまり、行を「所有」し、そのパラメーターを取得する)を実現する方法はありますか?

18
Paul Oyster

このようにしてみてください

UPDATE `lastid` SET `idnum` =  (SELECT `id` FROM `history` ORDER BY `id` DESC LIMIT 1);

上記のコードは私のために働きました

10
charles

これを行うプロシージャを作成できます。

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;
6
Quassnoi

まったく同じ問題があります。代わりに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ステートメントでのみ使用できます

EditMariaDBにUPDATE ... RETURNINGサポートを追加するタスク(低優先度)があります

1
Marco Roy

単一のクエリを探している場合、それは起こり得ません。 UPDATE関数は、具体的には更新されたアイテムの数のみを返します。同様に、SELECT関数はテーブルを変更せず、戻り値のみを変更します。

プロシージャを使用すると、実際にはプロシージャが1つの関数に変換され、ロックが問題になる場合に便利です。最大の懸念がネットワークトラフィックである場合(つまり、渡されるクエリが多すぎる場合)、この手順を使用します。サーバーの過負荷が懸念される場合(つまり、DBの負荷が大きすぎる)、プロシージャの余分なオーバーヘッドによって状況が悪化する可能性があります。

1
Paulo

単一の呼び出し部分についてはわかりませんが、説明しているのはロックです。ロックはリレーショナルデータベースの重要な要素です。

行をロックして読み取り、MySQLで更新する詳細はわかりませんが、 mysql lock documentation を少し読むだけで、あらゆる種類のロックベースの操作を実行できます。

locks のpostgres文書には、テーブルのロック、テーブルの読み取り、テーブルの変更など、実行する操作を正確に説明する優れた例があります。

0
Daniel
UPDATE tasks
SET guid = %d, params = @params := params
WHERE guid = 0 LIMIT 1;

値が効果的に変更されたかどうかに応じて、1または0を返します。

SELECT @params AS params;

これは、接続から変数を選択するだけです。

差出人: ここ

0
jogaco