mysql锁表机制及相关优化

(该文章为方便本身查阅,也但愿对你们有所帮助,转载于互联网)
一、 锁机制
当前MySQL支持 ISAM , MyISAM, MEMORY (HEAP) 类型表的 表级锁BDB 表支持 页级锁InnoDB 表支持 行级锁
不少时候,能够经过经验来猜想什么样的锁对应用程序更合适,不过一般很难说一个锁比别的更好,这全都要依据应用程序来决定,不一样的地方可能须要不一样的锁。
想要决定是否须要采用一个支持 行级锁的存储引擎,就要看看应用程序都要作什么,其中的查询、更新语句是怎么用的。例如, 不少的web应用程序大量的作查询,不多删除,主要是基于索引的更新,只往特定的表中插入记录采用基本的MySQL的 MyISAM 表就很合适了。
MySQL中对表级锁的存储引擎来讲是释放死锁的。避免死锁能够这样作到:在任何查询以前先请求锁,而且按照请求的顺序锁表。
1)MySQL中用于 WRITE(写) 的表锁的实现机制以下:
若是表没有加锁,那么就加一个写锁。
不然的话,将请求放到写锁队列中。
2)MySQL中用于 READ(读) 的表锁的实现机制以下:
若是表没有加写锁,那么就加一个读锁。
不然的话,将请求放到读锁队列中。
当锁释放后,写锁队列中的线程能够用这个锁资源,而后才轮到读锁队列中的线程程。
这就是说,若是表里有不少更新操做的话,那么 Select 必须等到全部的更新都完成了以后才能开始。
如今版本的MySQL能够经过状态变量table_locks_waited 和table_locks_immediate 来分析系统中的锁表争夺状况:
mysql> show status like 'table%';
+-----------------------+----------+
| Variable_name         | Value    |
+-----------------------+----------+
| Table_locks_immediate | 15184994 |
| Table_locks_waited    | 20108    |
+-----------------------+----------+
2 rows in set (0.00 sec)
在 MySQL 3.23.7(在Windows上是3.23.25)之后,在 MyISAM 表中只要没有冲突的Insert 操做,就能够无需使用锁表自由地并行执行Insert 和Select 语句。也就是说,能够在其它客户端正在读取MyISAM 表记录的同时时插入新记录。若是数据文件的中间没有空余的磁盘块的话,就不会发生冲突了,由于这种状况下全部的新记录都会写在数据文件的末尾(当在表的中间作删除或者更新操做时,就可能致使空洞)。当空洞被新数据填充后,并行插入特性就会自动从新被启用了。
mysql>lock  tables real_table  write, insert_table  write;
mysql> insert  into  real_table  select * from insert_table;
mysql> truncate  table  insert_table;
mysql> unlock  tables; (本身斟酌)
InnoDB 使用行级锁,BDB 使用页级锁。对于 InnoDB 和 BDB 存储引擎来讲,是可能产生死锁的。这是由于 InnoDB 会自动捕获行锁,BDB 会在执行 SQL 语句时捕获页锁的,而不是在事务的开始就这么作。
行级锁的优势有: (innodb)
在不少线程请求不一样记录时减小冲突锁。
事务回滚时减小改变数据。
使长时间对单独的一行记录加锁成为可能。
行级锁的缺点有:
比页级锁和表级锁消耗更多的内存。
当在大量表中使用时,比页级锁和表级锁更慢,由于他须要请求更多的锁资源。
当须要频繁对大部分数据作GROUP BY 操做或者须要频繁扫描整个表时,就明显的比其它锁更糟糕。
-----------------------------------------------------------------------------------------
使用更高层的锁的话,就能更方便的支持各类不一样的类型应用程序,由于这种锁的开销比行级锁小多了。
表级锁在下列几种状况下比页级锁行级锁更优越:
不少操做都是读表。
在严格条件的索引上读取和更新,当更新或者删除能够用单独的索引来读取获得时:
Update tbl_name SET column=value Where unique_key_col=key_value;    
Delete FROM tbl_name Where unique_key_col=key_value;    
Select 和 Insert 语句并发的执行,可是只有不多的 Update 和 Delete 语句。
不少的扫描表和对全表的 GROUP BY 操做,可是没有任何写表。

二、 锁表
为了能有快速的锁,MySQL除了 InnoDB 和 BDB 这两种存储引擎外,全部的都是用表级锁(而非页、行、列级锁)。
对于 InnoDB 和 BDB 表,MySQL只有在指定用 LOCK TABLES 锁表时才使用表级锁。在这两种表中,建议最好不要使用 LOCK TABLES,由于 InnoDB 自动采用行级锁,BDB 用页级锁来保证事务的隔离。
若是数据表很大,那么在大多数应用中表级锁会比行级锁好多了,不过这有一些陷阱。
表级锁让不少线程能够同时从数据表中读取数据,可是若是另外一个线程想要写数据的话,就必需要先取得排他访问。正在更新数据时,必需要等到更新完成了,其余线程才能访问这个表。
更新操做一般认为比读取更重要,所以它的优先级更高。不过最好要先确认,数据表是否有很高的 Select 操做,而更新操做并不是很‘急需’。
表锁锁在一个线程在等待,由于磁盘空间满了,可是却须要有空余的磁盘空间,这个线程才能继续处理时就有问题了。这种状况下,全部要访问这个出问题的表的线程都会被置为等待状态,直到有剩余磁盘空间了。
表锁在如下设想状况中就不利了:
一个客户端提交了一个须要长时间运行的 Select 操做。
其余客户端对同一个表提交了 Update 操做,这个客户端就要等到 Select 完成了才能开始执行。
其余客户端也对同一个表提交了 Select 请求。因为 Update 的优先级高于 Select,因此 Select 就会先等到 Update 完成了以后才开始执行,它也在等待第一个 Select 操做。

下列所述能够减小表锁带来的资源争夺:
让 Select 速度尽可能快,这可能须要建立一些摘要表。
启动 mysqld 时使用参数 --low-priority-updates。这就会让更新操做的优先级低于 Select。这种状况下,在上面的假设中,第二个 Select 就会在 Insert 以前执行了,并且也无需等待第一个Select 了。
能够执行 SET LOW_PRIORITY_UpdateS=1 命令,指定全部的更新操做都放到一个指定的连接中去完成。
用 LOW_PRIORITY 属性来下降 Insert,Update,Delete 的优先级。
用 HIGH_PRIORITY 来提升 Select 语句的优先级。
从MySQL 3.23.7 开始,能够在启动 mysqld 时指定系统变量 max_write_lock_count 为一个比较低的值,它能强制临时地提升表的插入数达到一个特定值后的全部 Select 操做的优先级。它容许在 WRITE 锁达到必定数量后有 READ 锁。
当 Insert 和 Select 一块儿使用出现问题时,能够转而采用 MyISAM 表,它支持并发的Select 和 Insert 操做。
当在同一个表上同时有插入和删除操做时,Insert DELAYED 可能会颇有用。
当 Select 和 Delete 一块儿使用出现问题时,Delete 的 LIMIT 参数可能会颇有用。
执行 Select 时使用 SQL_BUFFER_RESULT 有助于减短锁表的持续时间.
如下是MySQL锁的一些建议: 只要对同一个表没有大量的更新和查询操做混在一块儿,目前的用户并非问题。 执行 LOCK TABLES 来提升速度(不少更新操做放在一个锁之中比没有锁的不少更新快多了)。将数据拆分开到多个表中可能也有帮助。 当MySQL碰到因为锁表引发的速度问题时,将表类型转换成 InnoDB 或 BDB 可能有助于提升性能。
相关文章
相关标签/搜索