MYSQL加锁的测验

 

 存储引擎  支持的锁定级别 php

myisam      表级别 java

memory     表级别 mysql

  inndb       行级别 程序员

 bdb:        页级别 sql

 

lock锁定类型数据库

 锁定方式            目的浏览器

 读锁                   本身与其余线程只能读取该表缓存

  写锁                  只有当前线程可以对表进行写入操做(其余线程也没法读这部分数据)性能优化

 

 

读锁的英文叫法是shared locks,shared是共享的意思,共享锁,就是全部用户均可以共享进行读(包括加锁的用户),不能写。服务器

 

写锁的英文叫法是Exclusive Locks,Exclusive是独有、排外的意思,只有本身(加锁的用户)才能进行些写入操做,其余用户只能读。有些书籍中有不一样叫法,好比互斥锁、排他锁。

 

纠正一下:之前理解错误了。加了排他锁定,其余事务是没法读取数据的。网上的资料比较零散。

最近看了jim Gray那本《事务处理概念与技术》,里面提到排他锁时:保留对该节点写的权利,防止其余事务在该节点及其后代节点加{x,u,s,six,is,ix}锁。

 

提到的s就是共享锁了,既然防止其余事务加s锁,那么其余线程是没法读的(全部线程获取数据以前必须先申请锁才能操做)。文章下面加的试验也会证实了这点。

 

ps:看来总结也好,加深了理解,若是不总结,也不会发现细节理解误差。

 

 

 测试一:测验读锁

 运行一个读锁:“lock table `cat` READ”

而后尝试使用update语句操做 :

update `cat` set remark= 'ceshi'

 

报错以下:

 

Table 'a' was locked with a READ lock and can't be updated

如今解锁(针对当前线程锁定的全部表解锁):"unlock tables" 

 

而后再次运行update语句,报错消失。完成更新操做。说明已经解除读锁了(能够进行更新) 

 

 测验二:测验写锁 

一、 我在一个客户端SQLyog中运行一个写锁sql:LOCK TABLE cat WRITE;

二、另外开一个客户端(线程),尝试运行更新:

update `cat` set remark= 'jgjgjg'

 

状况:由于使用了写锁,只有本身可以修改数据,其余线程没法执行update操做,此时服务器端的php程序一直等待数据库给予响应结果,数据被锁定了,根本无法执行sql语句,处于等待中,数据库并不会报错,由于这原本就是一个很正常的状况,须要等待释放锁才能执行update操做,其实大并发环境下就是这种状况(不少用户同时在执行sql操做,有的加了写锁定),因而速度就慢下来了。

结果phpmyadmin一直处于等待中,等待服务器给予客户端(浏览器)数据,截图以下:

 

 

 

 经验:使用phpmyadmin没法模拟出一个线程的状况。由于每次php运行完毕后,与数据库的链接就会自动断开(php脚本特性)。

而SQLyog这样的工具可以保持链接不断掉。因此,测验写锁的时候彻底可使用同一个工具测验出来。

 

 

 增长测验:测验加写锁后,其余事务没法读数据的状况

一样也是在SQLyog这样的工具中运行:LOCK TABLE cat WRITE

 

由于加了x锁后,其余事务是没法得到s锁,因此根本没法读数据。phpmyadmin这边查询这个表,都是等待状态。

 

 

 

 下面我在SQLyog释放掉写锁后,phpmyadmin这边就能读取数据了

 

 

 

 

 

 

 

 

 

 

 

 

InnoDB使用行锁定,BDB使用页锁定。对于这两种存储引擎,均可能存在死锁。这是由于,在SQL语句处理期间,InnoDB自动得到行锁定和BDB得到页锁定,而不是在事务启动时得到。

 

update语句默认比select语句优先权高。能够修改,在启动mysql的时候加上参数,用--low-priority-updates启动mysqld 

 

 

在大流量、大数量的网站,每每瓶颈不在于具体的语言,其实.net、java、php等语言速度的差异是有,可是很小,忽略不计。每每瓶颈在于数据库。我是这样理解:

 


$conn->query("update where ....");

...php其余代码

 

//php须要等待数据库(好比mysql)给予返回结果,才能继续往下面执行代码,但里mysql被锁定了,一直没有执行完毕。因此卡死了,一直在等待中。这就是为何语言不是瓶颈,瓶颈每每在数据库(数据量大的时候,数据库压力很大),这就是同步执行,须要等到上面代码执行完毕才能继续执行,之前听过阿里巴巴的分享,使用一种异步执行方案。并行加载数据,那么代码的执行耗时取决于最耗时的操做(由于全部操做都是并行开始运行)



 

其余测验办法:还能够开多个mysql命令行界面来测验。每一个界面就是一个session。

 

 

 

 

 

关于大表查询少用left join的缘由

进行select查操做,加的是共享锁(对整个表仍是对行,要看什么存储引擎)。共享锁,则其余线程只能读数据。那么insert,update操做就会阻塞,等待select操做完成后释放掉共享锁后,这些线程才能进行写数据操做。

若是使用left join进行关联查询,一张表的数据量大,就会致使copyingd table操做了,意思是要先复制一张临时表,在临时表上面进行计算操做。这个时间比较长,就会阻塞掉其余线程的写入操做,一直处在等待状态。须要进行写入的线程越多,那么越多的线程等待。

 

解决办法是:要迅速的查询,拆分红多步骤来操做,这样就算是加读锁的时候,也是针对当前操做的表。操做释放后,能够快速的释放掉锁。

 

我想到用现实生活中哲学来理解:一次干多件事情,固然是爽,可是很是揪心,搞的复杂,影响的面广,大面积的受到影响。若是拆分红小部分,一次干一小部分,那么受到影响的面积小。逐个逐个来分解任务。

 

在实际场景中,left join致使的阻塞其余线程的写操做的场景,恰好被我遇到了:

 

上面是show processlist命令查看出来的,这个命令能够查看mysql当前有哪些查询线程,会列出查询的语句出来。

 

上面状况显示,好几个insert操做被阻塞掉,一直在延迟,time项若是我没理解错的话,就是已经等待了这么多秒数了。

信息显示:waiting for table level lock。更新操做须要先获取锁(myisam存储引擎只支持表级别的锁,因此先获取表锁)。

 

 

问:究竟是什么状况致使没法获取表锁?

确定是其余线程在对别加了锁,一直没有执行完毕。从下面这张图能看出是什么缘由:

显示的状态栏表示Coping to tmp table,正在将数据复制到临时表(tmp table)。左侧显示是查询语句,是left join。

貌似进入死锁状态了,a想要获取表的锁,才能继续操做。b线程也要获取,可是有个线程一直没有释放掉。

 

什么状况下会出现 copying to tmp table的操做呢?

有英文这样解释:

Copying to tmp table on disk The temporary result set was larger than tmp_table_size and the thread is now changing the in memory-based temporary table to a disk based one to save memory.

 

临时结果比tmp_table_size(这是一个内存缓存区)要大,存不下了,就会保持到磁盘去。

方案:

一、能够考虑把这个myisam存储引擎调整为innodb,innodb就支持行锁。

 

二、可是我以为本质仍是要减小left join查询,须要这样查询,拆分红多条sql,分步骤来执行会更好。

 

在互联网的应用结构中。联表查询,仍是要慎重,由于数据库是共享资源,不少应用程序都要来访问。一旦一个线程锁定数据表了,就会形成其余线程操做数据被阻塞了。

 

因此思想是尽可能快速完成查询。传统的数据库开发中使用复合查询,尽可能一条sql能够完成不少事情的思想。在互联网是不要这样子作。

 

拆分红多条sql进行查询,应用程序编码仍是增长了不少复杂度,原本一条sql丢入到query($sql)中就完成,如今要分红多个步骤。程序员会以为麻烦。

不过,为了性能优化,是要这样子。数据库资源毕竟有限。有时候程序员调整一下思路,对于数据库压力的缓解是很大的。

相关文章
相关标签/搜索