patternsqlMinor
Minimize locking on UPDATE with multiple WHERE columns
Viewed 0 times
minimizeupdatecolumnswithwherelockingmultiple
Problem
I have a problematic query that's causing a lock timeout:
I have two issues here:
-
I have multiple servers committing the query simultaneously, they lock each other out and I get lock timeout or even deadlock sometimes. Optimally the servers should update mutually exclusive rows so locking shouldn't happen at all. Is there a way I can skip any locked row in the update?
-
If I can't avoid locking, and I already have an index for col1 and another one for col2, will Innodb lock all rows that satisfy any condition in the WHERE clause or only the ones that satisfy both conditions? If the answer is the former, can I add an index for the two columns together or do I also need to remove the indexes that I have (for each column separately)?
UPDATE SET col1=
WHERE col1 IS NULL AND col2 >
ORDER BY col2
LIMIT 100I have two issues here:
-
I have multiple servers committing the query simultaneously, they lock each other out and I get lock timeout or even deadlock sometimes. Optimally the servers should update mutually exclusive rows so locking shouldn't happen at all. Is there a way I can skip any locked row in the update?
-
If I can't avoid locking, and I already have an index for col1 and another one for col2, will Innodb lock all rows that satisfy any condition in the WHERE clause or only the ones that satisfy both conditions? If the answer is the former, can I add an index for the two columns together or do I also need to remove the indexes that I have (for each column separately)?
Solution
You will need to lock all the rows yourself before each
See the MySQL Documentation on
In your particular case, you would do this:
INDEXING
I have many posts on the subject of
UPDATE 2013-03-17 19:21 EDT
Since you have 9 WebServers hitting the DB Server, try this
On WebServer1 run
On WebServer2 run
On WebServer3 run
All the way to WebServer9, run
You will have to place some PHP header file that unique identifies which machine runs which version of the query.
UPDATE.See the MySQL Documentation on
SELECT ... LOCK FOR UPDATE. This performs an exclusive lock on all the rows you pass through. Then, you can follow up with the needed UPDATE against the table.In your particular case, you would do this:
SELECT * FROM
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 100;
UPDATE SET row1=
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 100INDEXING
- You should index the table fully to support all possible ways you will be querying the data. Notwithstanding, you must alternate between
SELECT ... FOR UPDATEandUPDATE.
- Since you have both
row1androw2in the WHERE clause, you should have an index with both columns in it.
- There is one warning: If these columns are indexed, expect some slowness because the column is being updated and the BTREE index pages are being updated per row. You should also expect rapid growth of the insert buffer section of ibdata1 (See InnoDB Map)
I have many posts on the subject of
SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARED MODE.- Case Study I went through with @RedBlueThing
- Reasons for occasionally slow queries?
- Trouble deciphering a deadlock in an innodb status log
- Will these two queries result in a deadlock if executed in sequence?
Aug 08, 2011: Are InnoDB Deadlocks exclusive to INSERT/UPDATE/DELETE?
Oct 18, 2011: Preventing mysql deadlocks in your php application that uses SELECT… LOCK IN SHARE MODE
Jan 02, 2012: LOCK IN SHARE MODE
Nov 19, 2012: How long can Deadlock info hold in innodb status page?
Dec 13, 2012: MySQL InnoDB locks primary key on delete even in READ COMMITTED
Feb 03, 2013: MySQL InnoDB locking on combined UPDATE-JOIN statements
Mar 12, 2013: How I prevent deadlock occurrence in my application?
UPDATE 2013-03-17 19:21 EDT
Since you have 9 WebServers hitting the DB Server, try this
On WebServer1 run
SELECT * FROM
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 0,100;
UPDATE SET row1=
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 0,100;On WebServer2 run
SELECT * FROM
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 100,100;
UPDATE SET row1=
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 100,100;On WebServer3 run
SELECT * FROM
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 200,100;
UPDATE SET row1=
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 200,100;All the way to WebServer9, run
SELECT * FROM
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 800,100;
UPDATE SET row1=
WHERE row1 IS NULL AND row2 >
ORDER BY row2 LIMIT 800,100;You will have to place some PHP header file that unique identifies which machine runs which version of the query.
Code Snippets
SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 0,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 0,100;SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 100,100;SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 200,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 200,100;SELECT * FROM <some_table>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 800,100;
UPDATE <some_table> SET row1=<some value>
WHERE row1 IS NULL AND row2 > <some value>
ORDER BY row2 LIMIT 800,100;Context
StackExchange Database Administrators Q#36885, answer score: 2
Revisions (0)
No revisions yet.