ITPub博客

首页 > 数据库 > MySQL > mysql锁问题的研究

mysql锁问题的研究

原创 MySQL 作者:oraclesuperman 时间:2015-07-21 14:16:55 0 删除 编辑

MYISAM表锁:


mysql> show status like 'table%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Table_locks_immediate      | 70    |
| Table_locks_waited         | 0     |
| Table_open_cache_hits      | 0     |
| Table_open_cache_misses    | 0     |
| Table_open_cache_overflows | 0     |
+----------------------------+-------+
5 rows in set (0.00 sec)

Table_locks_immediate值越大表示表级锁定越严重。

mysql> lock table t1 write;
Query OK, 0 rows affected (0.00 sec)


mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)


session 1:

mysql> lock table t1 read;
Query OK, 0 rows affected (0.00 sec)

没加读锁的表不能访问:

mysql> select * from t;
ERROR 1100 (HY000): Table 't' was not locked with LOCK TABLES


mysql> select * from t1;
+------+
| name |
+------+
| 111  |
+------+
1 row in set (0.00 sec)

通过别名的访问也会报错:

mysql> select * from t1 as t2;
ERROR 1100 (HY000): Table 't2' was not locked with LOCK TABLES

需要锁定别名:

mysql> lock table t1 as  a read,t1 as t2 read;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 as t2;
+------+
| name |
+------+
| 111  |
+------+
1 row in set (0.00 sec)


session 2:

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|    32768 |
+----------+
1 row in set (0.02 sec)

mysql> select count(*) from t1;
+----------+
| count(*) |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)


mysql> show variables like 'concurrent_in%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| concurrent_insert | AUTO  |
+-------------------+-------+
1 row in set (0.00 sec)

mysql> show variables like 'LOW_p%';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| low_priority_updates | OFF   |
+----------------------+-------+
1 row in set (0.00 sec)


INNODB锁争用的问题:

mysql> show status like 'innodb_row_l%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0     |
| Innodb_row_lock_time          | 0     |
| Innodb_row_lock_time_avg      | 0     |
| Innodb_row_lock_time_max      | 0     |
| Innodb_row_lock_waits         | 0     |
+-------------------------------+-------+
5 rows in set (0.00 sec)


mysql> select * FROM information_schema.INNODB_LOCKS;
Empty set (0.00 sec)

mysql> select * FROM information_schema.INNODB_LOCK_WAITS;
Empty set (0.00 sec)

mysql> create table innodb_monitor(a int) engine=innodb;
Query OK, 0 rows affected, 1 warning (0.07 sec)

mysql> show engine innodb status\G;
*************************** 1. row ***************************
  Type: InnoDB
  Name:
Status:
=====================================
2015-07-21 13:19:48 7f4102434700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 22 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 2 srv_active, 0 srv_shutdown, 10326 srv_idle
srv_master_thread log flush and writes: 10328
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 21
OS WAIT ARRAY INFO: signal count 21
Mutex spin waits 10, rounds 300, OS waits 10
RW-shared spins 11, rounds 330, OS waits 11
RW-excl spins 0, rounds 0, OS waits 0
Spin rounds per wait: 30.00 mutex, 30.00 RW-shared, 0.00 RW-excl
------------
TRANSACTIONS
------------
Trx id counter 14893
Purge done for trx's n:o < 14886 undo n:o < 0 state: running but idle
History list length 283
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 3, OS thread handle 0x7f41023f3700, query id 323 196.128.1.123 root cleaning up
---TRANSACTION 14889, not started
MySQL thread id 2, OS thread handle 0x7f4102434700, query id 337 localhost root init
show engine innodb status
---TRANSACTION 14873, not started
mysql tables in use 1, locked 1
MySQL thread id 1, OS thread handle 0x7f4102475700, query id 329 localhost root cleaning up
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
521 OS file reads, 64 OS file writes, 30 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 1.14 writes/s, 0.59 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 276671, node heap has 0 buffer(s)
0.00 hash searches/s, 0.77 non-hash searches/s
---
LOG
---
Log sequence number 370556050
Log flushed up to   370556050
Pages flushed up to 370556050
Last checkpoint at  370556050
0 pending log writes, 0 pending chkp writes
21 log i/o's done, 0.23 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------


session 1:

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t where id=178;
+-----+------+
| id  | name |
+-----+------+
| 178 | aaa  |
+-----+------+
1 row in set (0.00 sec)

mysql> select * from t where id=178 lock in share mode;
+-----+------+
| id  | name |
+-----+------+
| 178 | aaa  |
+-----+------+
1 row in set (0.00 sec)

mysql> update t set name='rrrrrr' where id=178;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction


处于等待状态


session 2:
mysql>  update t set name='rrrrrr' where id=178;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
死循环退出

session 1执行成功。

在没有索引的情况下,INNODB会对所有的记录都加锁:

session 1:
mysql> create table tab_no_index(id int,name varchar(10)) engine=innodb;
Query OK, 0 rows affected (0.07 sec)

mysql> insert into tab_no_index values (1,'1'),(2,'2'),(3,'3'),(4,'4');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tab_no_index where id=1;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from tab_no_index where id=1 for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)


session 2:

mysql> select * from tab_no_index where id=2;
+------+------+
| id   | name |
+------+------+
|    2 | 2    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from tab_no_index where id=2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction


有索引的情况:

session 1:

mysql> create table tab_with_index(id int,name varchar(10)) engine=innodb;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into tab_with_index values (1,'1'),(2,'2'),(3,'3'),(4,'4');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> alter table tab_with_index add index id(id);
Query OK, 0 rows affected (12.55 sec)
Records: 0  Duplicates: 0  Warnings: 0


mysql> select * from tab_with_index where id=1;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from tab_with_index where id=1 for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)


session 2:

mysql> select * from tab_with_index where id=2;
+------+------+
| id   | name |
+------+------+
|    2 | 2    |
+------+------+
1 row in set (0.00 sec)

mysql> select * from tab_with_index where id=2 for update;
+------+------+
| id   | name |
+------+------+
|    2 | 2    |
+------+------+
1 row in set (0.00 sec)


如果是相同的索引键,是会出现锁冲突的:

mysql> truncate table tab_with_index;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into tab_with_index values(1,'1'),(1,'4');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> alter table tab_with_index add index id(id);
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0


session 1:

mysql> select * from tab_with_index where name='1' for update;
+------+------+
| id   | name |
+------+------+
|    1 | 1    |
+------+------+
1 row in set (0.00 sec)

session 2:

mysql> truncate table tab_with_index;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into tab_with_index values(1,'1'),(1,'4');
Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> alter table tab_with_index add index id(id);
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from tab_with_index where id=1 and name='4' for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction



next-key锁:

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set (0.00 sec)


mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|    32768 |
+----------+
1 row in set (0.03 sec)

mysql> create table t_test as select * from t;
Query OK, 32768 rows affected (0.68 sec)
Records: 32768  Duplicates: 0  Warnings: 0


mysql> delete from t where id > 101;
Query OK, 32704 rows affected (0.14 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)


session 1:

mysql> select * from t where id = 102 for update;
Empty set (0.00 sec)


session 2阻塞:

mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values(201,'aaa');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction


mysql> set autocommit = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> select count(*) from t;
+----------+
| count(*) |
+----------+
|       64 |
+----------+
1 row in set (0.00 sec)

mysql> delete from t where id >10;
Query OK, 56 rows affected (0.01 sec)

mysql> select * from t;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
|  3 | aaa  |
|  4 | bbb  |
|  6 | aaa  |
|  7 | bbb  |
|  8 | aaa  |
|  9 | bbb  |
+----+------+
8 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> create table t66 as select * from t where 1=0;
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into t66 select * from t where name='aaa';
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t66;
Empty set (0.00 sec)

mysql> select * from t;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
|  3 | aaa  |
|  4 | bbb  |
|  6 | aaa  |
|  7 | bbb  |
|  8 | aaa  |
|  9 | bbb  |
+----+------+
8 rows in set (0.00 sec)

mysql> update t set name='ccc' where name='aaa';
Query OK, 4 rows affected (20.98 sec)
Rows matched: 4  Changed: 4  Warnings: 0


mysql> show variables like 'innodb_table%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| innodb_table_locks | ON    |
+--------------------+-------+
1 row in set (0.00 sec)

mysql> show variables like 'innodb_lock_w%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |
+--------------------------+-------+
1 row in set (0.00 sec)


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29313086/viewspace-1743148/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: MYSQL SERVER优化
下一篇: mysql日志
请登录后发表评论 登录
全部评论

注册时间:2015-03-20

  • 博文量
    178
  • 访问量
    422831