MyISAM 表级锁
MyISAM 表级锁模式
MyISAM 两种表级锁:
- 表共享读锁 (Table Read Lock):不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求;
- 表独占写锁 (Table Write Lock):会阻塞其他用户对同一表的读和写操作;
MyISAM 锁模式:
- 由于 MyISAM 引擎采用表级锁,因此写操作与其他的读/写操作一定是串行的。
- MyISAM 读锁写锁优先级:默认情况下,写锁比读锁具有更高的优先级。锁优先给写锁队列中的请求,再给读队列中的请求。
- 由于 MyISAM 读写锁优先级,MyISAM 不太适合有大量更新操作和查询操作应用的原因。
MyISAM 表级锁问题与优化
MyISAM 可能存在的问题:
- 大量更新,读操作可能一直阻塞;
- 长时间运行的读操作,写操作可能饿死。
优化方法:
- 尽可能通过中间表等对 SQL 语句进行分解,使得读操作快速完成;
- 复杂查询安排在数据库空闲时间执行。
改变读锁和写锁的优先级:
- 通过指定启动参数
low-priority-updates,使 MyISAM 引擎默认给予读请求以优先的权利。 - 通过执行命令
SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。 - 通过指定
INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。 - 给系统参数
max_write_lock_count设置一个合适的值,当一个表的读锁达到这个值后,MySQL 就暂时将写请求的优先级降低,给读进程一定获得锁的机会。
MyISAM 加表锁方法
执行查询语句(SELECT)前,会自动给涉及的表加读锁;
在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁。
在自动加锁的情况下,MyISAM 总是一次获得 SQL 语句所需要的全部锁,这也正是 MyISAM 表不会出现死锁的原因。
MyISAM 存储引擎支持并发插入,以减少给定表的读和写操作之间的争用:
如果 MyISAM 表在数据文件中间没有空闲块,则行始终插入数据文件的末尾。在这种情况下,你可以自由混合并发使用 MyISAM 表的 INSERT 和 SELECT 语句而不需要加锁——你可以在其他线程进行读操作的时候,同时将行插入到 MyISAM 表中。文件中间的空闲块可能是从表格中间删除或更新的行而产生的。如果文件中间有空闲快,则并发插入会被禁用,但是当所有空闲块都填充有新数据时,它又会自动重新启用。要控制此行为,可以使用 MySQL 的 concurrent_insert 系统变量。
如果你使用 LOCK TABLES 显式获取表锁,则可以请求 READ LOCAL 锁而不是 READ 锁,以便在锁定表时,其他会话可以使用并发插入。
- 当 concurrent_insert 设置为 0 时,不允许并发插入。
- 当 concurrent_insert 设置为 1 时,如果 MyISAM 表中没有空洞(即表的中间没有被删除的行),MyISAM 允许在一个线程读表的同时,另一个线程从表尾插入记录。这也是 MySQL 的默认设置。
- 当 concurrent_insert 设置为 2 时,无论 MyISAM 表中有没有空洞,都允许在表尾并发插入记录。