MySQL server: 5.6.15
MySQL Cluster: 7.3.4
Running production multi-threaded application, with optimized queries - intermittently receiving "Lock wait timeout exceeded; try restarting transaction". The scenario has been filtered to 2 tables, and separate threads when they are accessing (SELECT and UPDATE) the same row of data on each table.
Application being a telecom application, the response time is very important, and keeping that in view, the connection timeout is set to 2 seconds and the command timeout is set to 2 seconds. "Lock wait timeout" is captured couple of time a day, and is not time dependent. Under production once MySQL ADO connection throws the exception; Dot Net application captures the exception, and re-runs the query and everything works fine.
I am planning to find a solution where the "wait lock" can be removed completely, or to get a better control, so to avoid the scenario (if possible).
Individual queries causing the "lock":
Query #1:
SELECT a_ID, Gender,
IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2,
IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2
FROM lusers WHERE Port = '1391' LIMIT 1;
Query #2:
UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id
SET l.Screen = '3', a.ScreenStatus = '3'
WHERE a.Id = '2';
My understanding:
Transaction A locks row #1
Transaction B locks row #2
Transaction A tries to lock row #1, but can't
Transaction B tries to lock row #2, but can't
Both transactions wait until "lock wait timeout kicks in"
To create the sample database with data, run the following:
DROP TABLE IF EXISTS acct;
CREATE TABLE acct (
Id int(11) NOT NULL AUTO_INCREMENT,
Acc_Number int(11) NOT NULL DEFAULT '0',
Grp_Id smallint(6) NOT NULL DEFAULT '0',
ScreenStatus int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (Id),
UNIQUE KEY GrpId_AccNumber (Grp_Id, Acc_Number)
) ENGINE=ndbcluster;
DROP TABLE IF EXISTS lusers;
CREATE TABLE lusers (
Id int(11) NOT NULL AUTO_INCREMENT,
a_Id int(11) NOT NULL DEFAULT '0',
Acc_Number int(11) NOT NULL DEFAULT '0',
Grp_Id smallint(6) NOT NULL DEFAULT '0',
Port int(11) NOT NULL DEFAULT '0',
Gender int(1) NOT NULL DEFAULT '0',
Screen int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (Id),
UNIQUE KEY GrpId_AccNumber (Grp_Id, Acc_Number),
UNIQUE KEY a_Id (a_Id),
UNIQUE KEY Port (Port)
) ENGINE=ndbcluster;
INSERT INTO acct (Acc_Number, Grp_Id, ScreenStatus ) VALUES ('231652', '1', '3');
INSERT INTO acct (Acc_Number, Grp_Id, ScreenStatus ) VALUES ('123456', '1', '3');
INSERT INTO lusers (a_Id, Acc_Number, Grp_Id, Port, Gender, Screen) VALUES ('1', '231652', '1', '1234', '1', '3');
INSERT INTO lusers (a_Id, Acc_Number, Grp_Id, Port, Gender, Screen) VALUES ('2', '123456', '1', '1345', '0', '3');
SELECT a_ID, Gender, IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2, IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2 FROM lusers WHERE Port = '1391' LIMIT 1;
UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id SET l.Screen = '3', a.ScreenStatus = '3' WHERE a.Id = '2';
EXPLAIN SELECT a_ID, Gender, IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2, IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2 FROM lusers WHERE Port = '1391' LIMIT 1;
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
| 1 | PRIMARY | lusers | eq_ref | Port | Port | 4 | const | 1 | NULL |
| 3 | SUBQUERY | l | eq_ref | GrpId_AccNumber | GrpId_AccNumber | 6 | const,const | 1 | NULL |
| 2 | SUBQUERY | a | eq_ref | GrpId_AccNumber | GrpId_AccNumber | 6 | const,const | 1 | NULL |
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
EXPLAIN UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id SET l.Screen = '3', a.ScreenStatus = '3' WHERE a.Id = '2';
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | l | eq_ref | a_Id | a_Id | 4 | const | 1 | NULL |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+
MySQL Cluster: 7.3.4
Running production multi-threaded application, with optimized queries - intermittently receiving "Lock wait timeout exceeded; try restarting transaction". The scenario has been filtered to 2 tables, and separate threads when they are accessing (SELECT and UPDATE) the same row of data on each table.
Application being a telecom application, the response time is very important, and keeping that in view, the connection timeout is set to 2 seconds and the command timeout is set to 2 seconds. "Lock wait timeout" is captured couple of time a day, and is not time dependent. Under production once MySQL ADO connection throws the exception; Dot Net application captures the exception, and re-runs the query and everything works fine.
I am planning to find a solution where the "wait lock" can be removed completely, or to get a better control, so to avoid the scenario (if possible).
Individual queries causing the "lock":
Query #1:
SELECT a_ID, Gender,
IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2,
IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2
FROM lusers WHERE Port = '1391' LIMIT 1;
Query #2:
UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id
SET l.Screen = '3', a.ScreenStatus = '3'
WHERE a.Id = '2';
My understanding:
Transaction A locks row #1
Transaction B locks row #2
Transaction A tries to lock row #1, but can't
Transaction B tries to lock row #2, but can't
Both transactions wait until "lock wait timeout kicks in"
To create the sample database with data, run the following:
DROP TABLE IF EXISTS acct;
CREATE TABLE acct (
Id int(11) NOT NULL AUTO_INCREMENT,
Acc_Number int(11) NOT NULL DEFAULT '0',
Grp_Id smallint(6) NOT NULL DEFAULT '0',
ScreenStatus int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (Id),
UNIQUE KEY GrpId_AccNumber (Grp_Id, Acc_Number)
) ENGINE=ndbcluster;
DROP TABLE IF EXISTS lusers;
CREATE TABLE lusers (
Id int(11) NOT NULL AUTO_INCREMENT,
a_Id int(11) NOT NULL DEFAULT '0',
Acc_Number int(11) NOT NULL DEFAULT '0',
Grp_Id smallint(6) NOT NULL DEFAULT '0',
Port int(11) NOT NULL DEFAULT '0',
Gender int(1) NOT NULL DEFAULT '0',
Screen int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (Id),
UNIQUE KEY GrpId_AccNumber (Grp_Id, Acc_Number),
UNIQUE KEY a_Id (a_Id),
UNIQUE KEY Port (Port)
) ENGINE=ndbcluster;
INSERT INTO acct (Acc_Number, Grp_Id, ScreenStatus ) VALUES ('231652', '1', '3');
INSERT INTO acct (Acc_Number, Grp_Id, ScreenStatus ) VALUES ('123456', '1', '3');
INSERT INTO lusers (a_Id, Acc_Number, Grp_Id, Port, Gender, Screen) VALUES ('1', '231652', '1', '1234', '1', '3');
INSERT INTO lusers (a_Id, Acc_Number, Grp_Id, Port, Gender, Screen) VALUES ('2', '123456', '1', '1345', '0', '3');
SELECT a_ID, Gender, IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2, IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2 FROM lusers WHERE Port = '1391' LIMIT 1;
UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id SET l.Screen = '3', a.ScreenStatus = '3' WHERE a.Id = '2';
EXPLAIN SELECT a_ID, Gender, IFNULL( ( SELECT a.Id FROM acct AS a WHERE a.Acc_Number = '231652' AND Grp_Id = '1' LIMIT 1), 0) AS AId2, IFNULL( ( SELECT Port FROM lusers AS l WHERE l.Acc_Number = '231652' AND l.Grp_Id = '1' LIMIT 1), 1000) AS Port2 FROM lusers WHERE Port = '1391' LIMIT 1;
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
| 1 | PRIMARY | lusers | eq_ref | Port | Port | 4 | const | 1 | NULL |
| 3 | SUBQUERY | l | eq_ref | GrpId_AccNumber | GrpId_AccNumber | 6 | const,const | 1 | NULL |
| 2 | SUBQUERY | a | eq_ref | GrpId_AccNumber | GrpId_AccNumber | 6 | const,const | 1 | NULL |
+----+-------------+--------+--------+-----------------+-----------------+---------+-------------+------+-------+
EXPLAIN UPDATE lusers AS l INNER JOIN acct as a ON l.a_Id = a.Id SET l.Screen = '3', a.ScreenStatus = '3' WHERE a.Id = '2';
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | l | eq_ref | a_Id | a_Id | 4 | const | 1 | NULL |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 4 | const | 1 | Using where |
+----+-------------+-------+--------+---------------+---------+---------+-------+------+-------------+