一、MYISAM表级锁
MyISAM存储引擎只支持表级锁的锁模式:有表级共享锁和表级排它锁
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。
所以对MyISAM表进行操作会有以下情况:
1.对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
2.对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
并发插入
原则上数据表有一个读锁时,其它进程无法对此表进行更新操作,但在一定条件下,MyISAM表也支持查询和插入操作的并发进行。MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0,1,2。
1 2 3 4 |
mysql> show variables like "%concurrent%"\G *************************** 1. row *************************** Variable_name: concurrent_insert Value: 1 |
1. 当concurrent_insert设置为0时,不允许并发插入
2. 当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。
3. 当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
MYISAM的锁调度
由于MySQL认为写请求一般比读请求要重要,所以如果有读写请求同时进行的话,MYSQL将会优先执行写操作。这样MyISAM表在进行大量的更新操作时(特别是更新的字段中存在索引的情况下),会造成查询操作很难获得读锁,从而导致查询阻塞。
我们可以通过一些设置来调节MyISAM的调度行为:
1、通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
2、通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
3、通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。
PS:上面3种方法都是要么更新优先,要么查询优先的方法。这里要说明的就是,不要盲目的给mysql设置为读优先,因为一些需要长时间运行的查询操作,也会使写进程“饿死”。只有根据你的实际情况,来决定设置哪种操作优先。这些方法还是没有从根本上同时解决查询和更新的问题
二、MYISAM表级锁实例
数据表gz_phone里有二百多万数据,字段id,phone,area,age。现在同时用多个客户端同时对该表进行操作分析。
当我用client 1进行一个比较长时间的读操作时,分别用client 2、3进行读和写操作并查看锁结果:
Client 1:读
1 2 |
Mysql> select count(*) from contact group by area 74638 rows in set (3 min 23.23 sec) |
Client 2:读
1 2 3 4 5 6 7 8 |
Mysql> select id,phone from contact limit 1000,5; Id | phone 1001 | 13456669856 1002 | 13456669856 1003 | 13456669856 1004 | 13456669856 1005 | 13456669856 5 rows in set (0.01 sec) |
Client 3:写
1 2 3 |
Mysql> update contact set phone=13288888888 where id=1001; Qeury OK, 0 rows affected (2 min 57.32 sec) Rows matched: 1 Changed: 1 Warings: 0 |
总结:说明当数据表有一个读锁时,其它进程的查询操作可以马上执行,但更新操作需等待读锁释放后才会执行。
当用Client 1进行一个较长时间的更新操作时,用Client 2,3分别进行读写操作
Clinet 1:写
1 2 3 |
Mysql> update contact set phone=13288888888; Qeury OK, 0 rows affected (3 min 7.02 sec) Rows matched: 2234433 Changed: 2234432 Warings: 0 |
Client 2:读
1 2 3 4 5 6 7 8 |
Mysql> select id,phone,area,age from contact limit 5; Id | phone | area | age 1 | 13288888888 | Beijing | 18 2 | 13288888888 | shanghai | 28 3 | 13288888888 | tianjing | 38 4 | 13288888888 | nanjing | 18 5 | 13288888888 | beijing | 28 5 rows in set ( 2 min 45.34 sec) |
Client 3:写
1 2 3 |
Mysql> update contact set phone=13266666666 where id=10; Qeury OK, 0 rows affected (3 min 27.32 sec) Rows matched: 1 Changed: 1 Warings: 0 |
总结:说明当数据表有一个写锁时,其它进程的读写操作都需等待读锁释放后才会执行。