Home » Mysql » MySQL UPDATE and SELECT in one pass

MySQL UPDATE and SELECT in one pass

Posted by: admin November 30, 2017 Leave a comment

Questions:

I have a MySQL table of tasks to perform, each row having parameters for a single task.
There are many worker apps (possibly on different machines), performing tasks in a loop.
The apps access the database using MySQL’s native C APIs.

In order to own a task, an app does something like that:

  • Generate a globally-unique id (for simplicity, let’s say it is a number)

  • UPDATE tasks
    SET guid = %d
    WHERE guid = 0 LIMIT 1

  • SELECT params
    FROM tasks
    WHERE guid = %d

  • If the last query returns a row, we own it and have the parameters to run

Is there a way to achieve the same effect (i.e. ‘own’ a row and get its parameters) in a single call to the server?

Answers:

try like this

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

above code worked for me

Questions:
Answers:

You may create a procedure that does it:

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;

Questions:
Answers:

If you are looking for a single query then it can’t happen. The UPDATE function specifically returns just the number of items that were updated. Similarly, the SELECT function doesn’t alter a table, only return values.

Using a procedure will indeed turn it into a single function and it can be handy if locking is a concern for you. If your biggest concern is network traffic (ie: passing too many queries) then use the procedure. If you concern is server overload (ie: the DB is working too hard) then the extra overhead of a procedure could make things worse.

Questions:
Answers:

I don’t know about the single call part, but what you’re describing is a lock. Locks are an essential element of relational databases.

I don’t know the specifics of locking a row, reading it, and then updating it in MySQL, but with a bit of reading of the mysql lock documentation you could do all kinds of lock-based manipulations.

The postgres documenation of locks has a great example describing exactly what you want to do: lock the table, read the table, modify the table.

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

It will return 1 or 0, depending on whether the values were effectively changed.

SELECT @params AS params;

This one just selects the variable from the connection.

From: here

Questions:
Answers:

I have the exact same issue. We ended up using PostreSQL instead, and UPDATE ... RETURNING:

The optional RETURNING clause causes UPDATE to compute and return value(s) based on each row actually updated. Any expression using the table’s columns, and/or columns of other tables mentioned in FROM, can be computed. The new (post-update) values of the table’s columns are used. The syntax of the RETURNING list is identical to that of the output list of SELECT.

Example: UPDATE 'my_table' SET 'status' = 1 WHERE 'status' = 0 LIMIT 1 RETURNING *;

Or, in your case: UPDATE 'tasks' SET 'guid' = %d WHERE 'guid' = 0 LIMIT 1 RETURNING 'params';

Sorry, I know this doesn’t answer the question with MySQL, and it might not be easy to just switch to PostgreSQL, but it’s the best way we’ve found to do it. Even 6 years later, MySQL still doesn’t support UPDATE ... RETURNING. It might be added at some point in the future, but for now MariaDB only has it for DELETE statements.

Edit: There is a task (low priority) to add UPDATE ... RETURNING support to MariaDB.