mysql锁表机制的概述

61次阅读
没有评论

共计 3949 个字符,预计需要花费 10 分钟才能阅读完成。

这篇文章主要介绍“mysql 锁表机制的概述”,在日常操作中,相信很多人在 mysql 锁表机制的概述问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”mysql 锁表机制的概述”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!

 
一、概述
 
MySQL 有三种锁的级别:页级、表级、行级。
 
MyISAM 和 MEMORY 存储引擎采用的是表级锁(table-level locking);BDB 存储引擎采用的是页面锁(page-level
locking),但也支持表级锁;InnoDB 存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。
 
MySQL 这 3 种锁的特性可大致归纳如下:
 
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高, 并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低, 并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。
 
二、MyISAM 表锁
 
MyISAM 存储引擎只支持表锁,是现在用得最多的存储引擎。
 
1、查询表级锁争用情况
 
可以通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析系统上的表锁定争夺:
mysql show status like lsquo;table% rsquo;;
+ mdash; mdash; mdash; mdash; mdash; mdash; mdash; ndash;+ mdash; mdash; mdash;-+
| Variable_name | Value |
+ mdash; mdash; mdash; mdash; mdash; mdash; mdash; ndash;+ mdash; mdash; mdash;-+
| Table_locks_immediate | 76939364 |
| Table_locks_waited | 305089 |
+ mdash; mdash; mdash; mdash; mdash; mdash; mdash; ndash;+ mdash; mdash; mdash;-+
2 rows in set (0.00 sec)Table_locks_waited 的值比较高,说明存在着较严重的表级锁争用情况。
 
2、MySQL 表级锁的锁模式
 
MySQL 的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write
Lock)。MyISAM 在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT 等)前,会自动给涉及的表加写锁。
 
所以对 MyISAM 表进行操作,会有以下情况:
 
a、对 MyISAM 表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。
b、对 MyISAM 表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。
 
下面通过例子来进行验证以上观点。数据表 gz_phone 里有二百多万数据,字段 id,phone,ua,day。现在同时用多个客户端同时对该表进行操作分析。
 
a、当我用客户端 1 进行一个比较长时间的读操作时,分别用客户端 2 进行读和写操作:
 
client1:
mysql select count(*) from gz_phone group by ua;
75508 rows in set (3 min 15.87 sec) client2:
select id,phone from gz_phone limit 1000,10;
+ mdash; mdash;+ mdash; mdash;-+
| id | phone |
+ mdash; mdash;+ mdash; mdash;-+
| 1001 | 2222 |
| 1002 | 2222 |
| 1003 | 2222 |
| 1004 | 2222 |
| 1005 | 2222 |
| 1006 | 2222 |
| 1007 | 2222 |
| 1008 | 2222 |
| 1009 | 2222 |
| 1010 | 2222 |
+ mdash; mdash;+ mdash; mdash;-+
10 rows in set (0.01 sec)
mysql update gz_phone set phone= rsquo;11111111111 prime;where id=1001;
Query OK, 0 rows affected (2 min 57.88 sec)
Rows matched: 1 Changed: 0 Warnings: 0
 
说明当数据表有一个读锁时,其它进程的查询操作可以马上执行,但更新操作需等待读锁释放后才会执行。
 
b、当用客户端 1 进行一个较长时间的更新操作时,用客户端 2,3 分别进行读写操作:
 
client1:
mysql update gz_phone set phone= rsquo;11111111111 prime;;
Query OK, 1671823 rows affected (3 min 4.03 sec)
Rows matched: 2212070 Changed: 1671823 Warnings: 0 client2:
mysql select id,phone,ua,day from gz_phone limit 10;
+ mdash;-+ mdash; mdash;-+ mdash; mdash; mdash; mdash; mdash; mdash;-+ mdash; mdash; mdash; mdash;+
| id | phone | ua | day |
+ mdash;-+ mdash; mdash;-+ mdash; mdash; mdash; mdash; mdash; mdash;-+ mdash; mdash; mdash; mdash;+
| 1 | 2222 | SonyEricssonK310c | 2007-12-19 |
| 2 | 2222 | SonyEricssonK750c | 2007-12-19 |
| 3 | 2222 | MAUI WAP Browser | 2007-12-19 |
| 4 | 2222 | Nokia3108 | 2007-12-19 |
| 5 | 2222 | LENOVO-I750 | 2007-12-19 |
| 6 | 2222 | BIRD_D636 | 2007-12-19 |
| 7 | 2222 | SonyEricssonS500c | 2007-12-19 |
| 8 | 2222 | SAMSUNG-SGH-E258 | 2007-12-19 |
| 9 | 2222 | NokiaN73-1 | 2007-12-19 |
| 10 | 2222 | Nokia2610 | 2007-12-19 |
+ mdash;-+ mdash; mdash;-+ mdash; mdash; mdash; mdash; mdash; mdash;-+ mdash; mdash; mdash; mdash;+
10 rows in set (2 min 58.56 sec) client3:
mysql update gz_phone set phone= rsquo;55555 prime;where id=1;
Query OK, 1 row affected (3 min 50.16 sec)
Rows matched: 1 Changed: 1 Warnings: 0
 
说明当数据表有一个写锁时,其它进程的读写操作都需等待读锁释放后才会执行。
 
3、并发插入
 
原则上数据表有一个读锁时,其它进程无法对此表进行更新操作,但在一定条件下,MyISAM 表也支持查询和插入操作的并发进行。
 
MyISAM 存储引擎有一个系统变量 concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为 0、1 或 2。
 
a、当 concurrent_insert 设置为 0 时,不允许并发插入。
b、当 concurrent_insert 设置为 1 时,如果 MyISAM 表中没有空洞(即表的中间没有被删除的行),MyISAM 允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是 MySQL 的默认设置。
c、当 concurrent_insert 设置为 2 时,无论 MyISAM 表中有没有空洞,都允许在表尾并发插入记录。
 
4、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 的读写分离技术

到此,关于“mysql 锁表机制的概述”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-28发表,共计3949字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)