MySQL锁机制详解及死锁处理方式

为了给高并发状况下的MySQL进行更好的优化,有必要了解一下MySQL查询更新时的锁表机制。mysql

1、概述 MySQL有三种锁的级别:页级、表级、行级。 MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认状况下是采用行级锁。 MySQL这3种锁的特性可大体概括以下: 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的几率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的几率最低,并发度也最高。 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度通常。sql

2、MyISAM表锁 MyISAM存储引擎只支持表锁,是如今用得最多的存储引擎。 但表级锁让多线程能够同时从数据表中读取数据,可是若是另外一个线程想要写数据的话,就必需要先取得排他访问。正在更新数据时,必需要等到更新完成了,其余线程才能访问这个表。(这种机制形成了并发读写容易出现表锁争夺而致使阻塞访问) 一、查询表级锁争用状况 能够经过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺: mysql> show status like 'table%'; +———————–+———-+ | Variable_name | Value | +———————–+———-+ | Table_locks_immediate | 76939364 | (表示能够当即获取锁的次数) | Table_locks_waited | 305089 | (表示不能当即获取锁,须要等待锁的次数;)
+———————–+———-+ 2 rows in set (0.00 sec) Table_locks_waited/(Table_locks_immediate+Table_locks_waited) 这个比例值越大说明表级锁争用的状况越严重。 例:比例值=0.01说明100次进程里就有一次是须要等待锁的进程;服务器

二、MySQL表级锁的锁模式 MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。MyISAM在执行查询语句(SELECT)前,会自动给涉及的全部表加读锁,在执行更新操做(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁。 因此对MyISAM表进行操做,会有如下状况: a、对MyISAM表的读操做(加读锁),不会阻塞其余进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操做。 b、对MyISAM表的写操做(加写锁),会阻塞其余进程对同一表的读和写操做,只有当写锁释放后,才会执行其它进程的读写操做。多线程

三、并发插入 原则上数据表有一个读锁时,其它进程没法对此表进行更新操做,但在必定条件下,MyISAM表也支持查询和插入操做的并发进行。 MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别能够为0、1或2。 a、当concurrent_insert设置为0时,不容许并发插入。 b、当concurrent_insert设置为1时,若是MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM容许在一个进程读表的同时,另外一个进程从表尾插入记录。这也是MySQL的默认设置。 c、当concurrent_insert设置为2时,不管MyISAM表中有没有空洞,都容许在表尾并发插入记录。 四、MyISAM的锁调度 因为MySQL认为写请求通常比读请求要重要,因此若是有读写请求同时进行的话,MYSQL将会优先执行写操做。这样MyISAM表在进行大量的更新操做时(特别是更新的字段中存在索引的状况下),会形成查询操做很难得到读锁,从而致使查询阻塞。 咱们能够经过一些设置来调节MyISAM的调度行为: a、经过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。 b、经过执行命令SET LOW_PRIORITY_UPDATES=1,使该链接发出的更新请求优先级下降。 c、经过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,下降该语句的优先级。 上面3种方法都是要么更新优先,要么查询优先的方法。这里要说明的就是,不要盲目的给mysql设置为读优先,由于一些须要长时间运行的查询操做,也会使写进程“饿死”。只有根据你的实际状况,来决定设置哪一种操做优先。 这些方法仍是没有从根本上同时解决查询和更新的问题。在一个有大数据量高并发表的mysql里,咱们还可采用另外一种策略来进行优化,那就是经过mysql主从(读写)分离来实现负载均衡,这样可避免优先哪种操做从而可能致使另外一种操做的堵塞。下面将用一个篇幅来讲明mysql的读写分离技术。并发

MyISAM使用的是 flock 类的函数,直接就是对整个文件进行锁定(叫作文件锁定),InnoDB使用的是 fcntl 类的函数,能够对文件中局部数据进行锁定(叫作行锁定),因此区别就是在这里。 另外MyISAM的数据表是按照单个文件存储的,能够针对单个表文件进行锁定,可是InnoDB是一整个文件,把索引、数据、结构所有保存在 ibdata 文件里,因此必须用行锁定。 死锁 所谓死锁<DeadLock>: 是指两个或两个以上的进程在执行过程当中, 因争夺资源而形成的一种互相等待的现象,若无外力做用,它们都将没法推动下去. 此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等竺的进程称为死锁进程. 表级锁不会产生死锁.因此解决死锁主要仍是真对于最经常使用的InnoDB. 遇到死锁的处理方式负载均衡

mysql -uxxx -pxxx -h服务器ip --port=服务器端口;(若是服务器设置了ip和端口访问的话,必定要带ip和端口)函数

mysql> show processlist; #查看正在执行的sql (show full processlist;查看所有sql) mysql> kill id #杀死sql进程; 若是进程太多找不到,就重启mysql吧 /ect/init.d/mysql restart 或/ect/init.d/mysql stop(若是关不掉就直接kill -9 进程id) 再/ect/init.d/mysql start 去看看mysql日志文件是否保存死锁日志: 经常使用目录:/var/log/mysqld.log;(该目录还有其它相关日志文件就都看看) 怎么解决仍是要看具体什么问题高并发

相关文章
相关标签/搜索