Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating a whole table without locking in MySQL

Tags:

mysql

locking

Running this update statement will lock every row in the table for 5 seconds.

UPDATE `audio_clips` SET activity = activity * 0.95;

Is there a way to do it in batches (internally to mysql), or to perform the statement without locking?

This is a field used to show what is currently popular on the site (like Reddit, Hacker News, etc). Whenever an audio_clip is played, activity is bumped by one. On a regular basis, we 'decay' the activity of each clip. I'm not bothered about updating atomically, as long as every row gets decayed.

like image 240
skattyadz Avatar asked Apr 08 '11 10:04

skattyadz


People also ask

How do I stop a MySQL table from locking?

Third option to prevent table locks with MySQL database is to use AUTOCOMMIT on the database level. This will prevent table locks from occurring unintentionally during report execution since all the transactions are committed after they are executed without additional commit commands.

Does update query locks the table MySQL?

A locking read, an UPDATE , or a DELETE generally set record locks on every index record that is scanned in the processing of an SQL statement. It does not matter whether there are WHERE conditions in the statement that would exclude the row.

How do you update an entire table in SQL?

Syntax: UPDATE table_name SET column_name1 = new_value1, column_name2 = new_value2 ---- WHERE condition; Here table_name is the name of the table, column_name is the column whose value you want to update, new_value is the updated value, WHERE is used to filter for specific data.

How do you select without locking the table?

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SELECT * FROM GFG_Demo_Table; Output: This query will also retrieve the same data directly, without using any table hint and without waiting for the UPDATE statement to release the lock it performed on the table.


2 Answers

I would definitely take a different approach.

Wouldn't it be possible to set a timestamp as the clip is played, and while bumping calculate the decay since that timestamp? When reading out for statistics, you should take the activity minus the decay since the last timestamp.

This way you still need only one update per clip played.

To make it concrete:

UPDATE `audio_clips` SET `lastview`=UNIX_TIMESTAMP(),
                   `activity`=1+`activity`*POW(0.9,(UNIX_TIMESTAMP()-`lastview`)/3600)
               WHERE `clipid`=$clipid

For a decay of 10% per hour and a bump of 1 per view.

To view current stats:

SELECT *,`activity`*POW(0.9,(UNIX_TIMESTAMP()-`lastview`)/3600) AS `current_activity`
       FROM `audio_clips`
like image 109
mvds Avatar answered Sep 29 '22 01:09

mvds


Ultimately, I ended up doing it in batches. It may not be perfectly scalable but in batches of 1000, each record is tied up for about 35ms. The whole process only takes 10 seconds of each hour.

Good enough.

like image 21
skattyadz Avatar answered Sep 28 '22 23:09

skattyadz