In my application, I have two queries that occur from time to time (from different processes), that cause a deadlock.
Query #1
UPDATE tblA, tblB SET tblA.varcharfield=tblB.varcharfield WHERE tblA.varcharfield IS NULL AND [a few other conditions];
Query #2
INSERT INTO tmp_tbl SELECT * FROM tblA WHERE [various conditions];
Both of these queries take a significant time, as these tables have millions of rows. When query #2 is running, it seems that tblA is locked in mode S. It seems that query #1 requires an X lock. Since this is incompatible with an S lock, query #1 waits for up to 30 seconds, at which point I get a deadlock:
Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
Based on what I’ve read in the documentation, I think I have a couple options:
- Set an index on tblA.varcharfield. Unfortunately, I think that this would require a very large index to store the field of varchar(512). (See edit below… this didn’t work.)
- Disable locking with
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;. I don’t understand the implications of this, and am worried about corrupt data. I don’t use explicit transactions in my application currently, but I might at some point in the future.
- Split my time-consuming queries into small pieces so that they can queue and run in MySQL without reaching the 30-second timeout. This wouldn’t really fix the heart of the issue, and I am concerned that when my database servers get busy that the problem will occur again.
- Simply retrying queries over and over again… not an option I am hoping for.
How should I proceed? Are there alternate methods I should consider?
EDIT: I have tried setting an index on varcharfield, but the table is still locking. I suspect that the locking happens when the UPDATE portion is actually executing. Are there other suggestions to get around this problem?
I was able to solve the issue by adding explicit
LOCK TABLEstatements around both queries. This turned out to be a better solution, since each query affects so many records, and that both of these are background processes. They now wait on each other.http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html
While this is an okay solution for me, it obviously isn’t the answer for everyone. Locking with
WRITEmeans that you cannotREAD. Only aREADlock will allow others toREAD.