ASSESSMENT
Your query is kind of dangerous to the MySQL Query Optimizer.
I have an old post (Problem with MySQL subquery). The question posed involved this query
DELETE FROM test WHERE id =
(SELECT id FROM (SELECT * FROM test) temp ORDER BY RAND() LIMIT 1);
Although the MySQL Query Parser will work with this query and accept it's syntax, the MySQL Documentation implies that some data may disappear during certain optimization phases. In your case, you are accessing just one row to get an id and then update that row. Notwithstanding, the remote possibility of accessing data from a subquery that might not return an id
because it can intermittently disappear does not strike me as transaction-safe, let alone thread-safe.
Your query looks similar to the query in that old post
- Non-SELECT query
- SELECT subquery
- Subquery uses LIMIT
This issues goes a limit beyond just being thread-safe or not. Even if it is, you should not trust MySQL's interpretation of grabbing an available seat in the middle of a subquery. You need your query to be transaction-safe.
SUGGESTION #1
My advice to you would be to rewrite this as three queries in a transaction.
Perhaps something like this:
START TRANSACTION;
SELECT id from seats WHERE taken is null limit 1 FOR UPDATE;
SELECT id INTO @available_id from seats WHERE taken is null limit 1;
UPDATE seats SET taken = 1 WHERE id = @available_id;
COMMIT;
or with two queries
START TRANSACTION;
SELECT id INTO @available_id from seats WHERE taken is null limit 1 FOR UPDATE;
UPDATE seats SET taken = 1 WHERE id = @available_id;
COMMIT;
For further info, please read MySQL Documentation on SELECT ... FOR UPDATE
.
SUGGESTION #2
I would also make sure that the seats
table has an index on the taken column.
If not, add this index
ALTER TABLE seats ADD INDEX (taken);
Do this in Dev/Staging Environment and test your query before doing this in Production.
GIVE IT A TRY !!!
update seats set taken = 1 where taken is null <order by whatever> limit 1;