北京SEO

mysql锁表机制分析与锁表问题

2019/10/10/17:36:54  阅读:2020  来源:谷歌SEO算法  标签: 黑猫SEO

mysql锁表就是为了更好的处理超大负载时的一个优化东西,下面我来给各位同学介绍一下mysql锁表机制与mysql锁表碰到的一些问题分析.

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

一、概述

MySQL有三种锁的级别:页级、表级、行级。

MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking);BDB存储引擎采用的是页面锁(page-levellocking),但也支持表级锁;InnoDB存储引擎既支持行级锁(row-level locking),也支持表级锁,但默认情况下是采用行级锁。

MySQL这3种锁的特性可大致归纳如下:

表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。

行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。

页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

二、MyISAM表锁

MyISAM存储引擎只支持表锁,是现在用得最多的存储引擎.

1、查询表级锁争用情况

可以通过检查table_locks_waited和table_locks_immediate状态变量来分析系统上的表锁定争夺,代码如下:

  1. mysql>showstatusliketable%’;
  2. +———————–+———-+
  3. |Variable_name|Value|
  4. +———————–+———-+
  5. |Table_locks_immediate|76939364|
  6. |Table_locks_waited|305089|
  7. +———————–+———-+

2 rows in set (0.00 sec)Table_locks_waited的值比较高,说明存在着较严重的表级锁争用情况。

2、MySQL表级锁的锁模式

MySQL的表级锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table WriteLock),MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁.

所以对MyISAM表进行操作,会有以下情况:

a、对MyISAM表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其它进程的写操作。

b、对MyISAM表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其它进程的读写操作。

下面通过例子来进行验证以上观点,数据表gz_phone里有二百多万数据,字段id,phone,ua,day。现在同时用多个客户端同时对该表进行操作分析.

a、当我用客户端1进行一个比较长时间的读操作时,分别用客户端2进行读和写操作.

client1,代码如下:

  1. mysql>selectcount(*)fromgz_phonegroupbyua;
  2. 75508rowsinset(3min15.87sec)client2:
  3. selectid,phonefromgz_phonelimit1000,10;
  4. +——+——-+
  5. |id|phone|
  6. +——+——-+
  7. |1001|2222|
  8. |1002|2222|
  9. |1003|2222|
  10. |1004|2222|
  11. |1005|2222|
  12. |1006|2222|
  13. |1007|2222|
  14. |1008|2222|
  15. |1009|2222|
  16. |1010|2222|
  17. +——+——-+
  18. 10rowsinset(0.01sec)
  19. mysql>updategz_phonesetphone=’11111111111′whereid=1001;
  20. QueryOK,0rowsaffected(2min57.88sec)
  21. Rowsmatched:1Changed:0Warnings:0

说明当数据表有一个读锁时,其它进程的查询操作可以马上执行,但更新操作需等待读锁释放后才会执行.

b、当用客户端1进行一个较长时间的更新操作时,用客户端2,3分别进行读写操作.

client1,代码如下:

  1. mysql>updategz_phonesetphone=’11111111111′;
  2. QueryOK,1671823rowsaffected(3min4.03sec)
  3. Rowsmatched:2212070Changed:1671823Warnings:0client2:
  4. mysql>selectid,phone,ua,dayfromgz_phonelimit10;
  5. +—-+——-+——————-+————+
  6. |id|phone|ua|day|
  7. +—-+——-+——————-+————+
  8. |1|2222|SonyEricssonK310c|2007-12-19|
  9. |2|2222|SonyEricssonK750c|2007-12-19|
  10. |3|2222|MAUIWAPBrowser|2007-12-19|
  11. |4|2222|Nokia3108|2007-12-19|
  12. |5|2222|LENOVO-I750|2007-12-19|
  13. |6|2222|BIRD_D636|2007-12-19|
  14. |7|2222|SonyEricssonS500c|2007-12-19|
  15. |8|2222|SAMSUNG-SGH-E258|2007-12-19|
  16. |9|2222|NokiaN73-1|2007-12-19|
  17. |10|2222|Nokia2610|2007-12-19|
  18. +—-+——-+——————-+————+
  19. 10rowsinset(2min58.56sec)client3:
  20. mysql>updategz_phonesetphone=’55555′whereid=1;
  21. QueryOK,1rowaffected(3min50.16sec)
  22. Rowsmatched:1Changed:1Warnings: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的读写分离技术.

杀掉被锁的表,代码如下:

SHOW PROCESSLIST查看数据库中表的状态,是否被锁.

  1. killid//杀掉被锁的表
  2. ===================================================
  3. setautocommit=0;
  4. select*fromt1whereuid='xxxx'forupdate//在有索引(例如uid)的情况下是行锁,否则是表锁
  5. insertintot1values(1,'xxxxx');
  6. commit;
  7. =====================================================
  8. locktablest1write|read;
  9. insertintot1values(2,'xxxxx');//只有insert
  10. unlocktables;

下面描述了一些方法来避免或减少表锁定造成的竞争:

· 试图使 SELECT 语句运行得更快,可能必须创建一些摘要(summary)表做到这点。

· 用--low-priority-updates启动mysqld。这将给所有更新(修改)一个表的语句以比SELECT语句低的优先级。在这种情况下,在先前情形的第2个SELECT语句将在UPDATE语句前执行,而不需要等候第1个 SELECT 完成.

· 可以使用SET_UPDATES=1语句指定具体连接中的所有更新应使用低优先级.

· 可以用LOW_PRIORITY属性给与一个特定的INSERT、UPDATE或DELETE语句较低优先级.

· 可以用HIGH_PRIORITY属性给与一个特定的SELECT语句较高优先级.

· 为max_write_lock_count系统变量指定一个低值来启动mysqld来强制MySQL在具体数量的插入完成后临时提高所有等待一个表的SELECT 语句的优先级,这样允许在一定数量的WRITE锁定后给出READ锁定.

· 如果你有关于INSERT结合SELECT的问题,切换到使用新的MyISAM表,因为它们支持并发的SELECT和INSERT.

· 如果你对同一个表混合插入和删除,INSERT DELAYED将会有很大的帮助.

· 如果你对同一个表混合使用 SELECT 和DELETE 语句出现问题,DELETE 的LIMIT 选项可以有所帮助.

· 对 SELECT 语句使用SQL_BUFFER_RESULT可以帮助使表锁定时间变短。

· 可以更改mysys/thr_lock.c中的锁代码以使用单一的队列。在这种情况下,写锁定和读锁定将具有相同的优先级,对一些应用程序会有帮助。

这里是一些MySQL中表锁定相关的技巧:

· 如果不混合更新与需要在同一个表中检查许多行的选择,可以进行并行操作.

· 可以使用 LOCK TABLES 来提高速度,因为在一个锁定中进行许多更新比没有锁定的更新要快得多,将表中的内容切分为几个表也可以有所帮助.

· 如果在MySQL中表锁定时遇到速度问题,可以将表转换为 InnoDB 或BDB 表来提高性能.

广告内容

mysql锁表机制分析与锁表问题 mysql锁表机制分析与锁表问题 mysql锁表机制分析与锁表问题

相关阅读

热门评论

爱互踩 爱互踩

爱互踩流量交换~

总篇数175

精选文章

RMAN中catalog和nocatalog区别介绍 小技巧:为Linux下的文件分配多个权限 zimbra8.5.1安装第三方签名ssl证书的步骤 解决mysql不能远程连接数据库方法 windows服务器mysql增量备份批处理数据库 mysql中slow query log慢日志查询分析 JavaScript跨域问题总结 Linux下负载均衡软件LVS配置(VS/DR)教程 mysql中权限参数说明 MYSQL(错误1053)无法正常启动

SEO最新算法