Please pardon a bit of a newbie question - I'm a developer attempting to play the role of a DBA, and a bit over my head at the moment.
The main issue I'm trying to deal with at the moment is that MySQL is showing me a lot of deadlock errors. We've been running for months without any, and after adding what we thought were fairly innocuous changes, we're suddenly seeing a dozen an hour.
The specific error we're seeing (table/column names scrubbed, we're using some JDBI you'll see in there as well):
------------------------
LATEST DETECTED DEADLOCK
------------------------
2014-05-21 19:11:13 2b4c3602a700
*** (1) TRANSACTION:
TRANSACTION 1327203423, ACTIVE 0 sec starting index read
mysql tables in use 3, locked 3
LOCK WAIT 4 lock struct(s), heap size 1248, 3 row lock(s)
MySQL thread id 6182129, OS thread handle 0x2b4c36683700, query id 2061701269 [host] [ip] [user] updating
/* WriteDAO.update */ UPDATE A SET t = 0, createdDate = '2014-05-21 19:11:13' WHERE uid = 1 AND tid = 100
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 109 page no 84 n bits 584 index `idx_A_tid` of table `core`.`A` trx id 1327203423 lock_mode X waiting
Record lock, heap no 167 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 8; hex 8000000000002740; asc '@;;
1: len 8; hex 8000000000002747; asc 'G;;
*** (2) TRANSACTION:
TRANSACTION 1327203438, ACTIVE 0 sec fetching rows
mysql tables in use 3, locked 3
6 lock struct(s), heap size 1248, 6 row lock(s)
MySQL thread id 6182028, OS thread handle 0x2b4c3602a700, query id 2061701279 [host] [ip] [user] updating
/* WriteDAO.update */ UPDATE A SET t = 0, createdDate = '2014-05-21 19:11:13' WHERE uid = 2 AND tid = 100
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 109 page no 84 n bits 584 index `idx_A_tid` of table `core`.`A` trx id 1327203438 lock_mode X
Record lock, heap no 167 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 8; hex 8000000000002740; asc '@;;
1: len 8; hex 8000000000002747; asc 'G;;
Record lock, heap no 168 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
0: len 8; hex 8000000000002740; asc '@;;
1: len 8; hex 800000000000274e; asc 'N;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 109 page no 6 n bits 344 index `PRIMARY` of table `core`.`A` trx id 1327203438 lock_mode X locks rec but not gap waiting
Record lock, heap no 63 PHYSICAL RECORD: n_fields 7; compact format; info bits 0
0: len 8; hex 800000000000274e; asc 'N;;
1: len 6; hex 00004f13d872; asc O r;;
2: len 7; hex 42000001e02f43; asc B /C;;
3: len 8; hex 8000000000002771; asc 'q;;
4: len 8; hex 8000000000002740; asc '@;;
5: len 8; hex 8000000000000000; asc ;;
6: len 5; hex 9992eb085c; asc \;;
*** WE ROLL BACK TRANSACTION (1)
The table A is fairly simple, with two indexes at the end:
CREATE TABLE A (
id BIGINT NOT NULL AUTO_INCREMENT,
uid BIGINT NOT NULL,
tid BIGINT NOT NULL,
t BIGINT NOT NULL,
createdDate DATETIME NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARACTER SET=utf8 COLLATE=utf8_unicode_ci;
CREATE INDEX idx_A_uid ON A (uid);
CREATE INDEX idx_A_tid ON A (tid);
We aren't running anything against these tables in a transaction, beyond what JDBI transactions do automatically via @SqlUpdate / @SqlQuery / etc annotations, e.g.:
@SqlUpdate("UPDATE A "+
" SET t = :t, createdDate = :createdDate "+
" WHERE uid = :uid AND tid = :tid")
public int update (@BindBean T t);
All of these queries run quite quickly (slow queries logs don't show anything over a second, and almost everything is much less than that). We don't have all that significant a load yet.
First question:
mysql tables in use 3, locked 3
Why is MySQL locking 3 tables to do an update on one? Does it consider the indexes to be tables as well in this output?
Second question:
RECORD LOCKS space id 109 page no 6 n bits 344 index `PRIMARY` of table `core`.`A` trx id 1327203438 lock_mode X locks rec but not gap waiting
Why is the primary key of A locked? We don't touch that column >at all<, except for the initial row creation. Notice that neither update statement is touching that column, and they should be operating against different rows even. We also use distributed hazelcast to obtain a distributed lock, so only one thread should ever be trying to access a given row for writing in this table at a time. Can a read lock on a row cause the write to deadlock? And even if it could, shouldn't the row level locking address this?
Third question: If MySQL needs to update a row in the index, does it lock the entire index like a table lock? Or does it do row level locking like the table its indexing?
Any suggestions for debugging this?
Thanks