SQL Server中SELECT会真的阻塞SELECT吗?
2017-01-04 23:06
344 查看
而且从最常见的锁模式的兼容性表,我们可以看到IS锁与S锁都是兼容的,也就是说SELECT查询是不会阻塞SELECT查询的。
现有的授权模式 | ||||||
请求的模式 | IS | S | U | IX | SIX | X |
意向共享(IS) | 是 | 是 | 是 | 是 | 是 | 否 |
共享(S) | 是 | 是 | 是 | 否 | 否 | 否 |
更新(U) | 是 | 是 | 否 | 否 | 否 | 否 |
意向排他(IX) | 是 | 否 | 否 | 是 | 否 | 否 |
意向排他共享(SIX) | 是 | 否 | 否 | 否 | 否 | 否 |
排他(X) | 否 | 否 | 否 | 否 | 否 | 否 |
CREATETABLETEST(OBJECT_IDINT,NAMEVARCHAR(8));
CREATEINDEXPK_TESTONTEST(OBJECT_ID)
DECLARE@IndexINT=0;
WHILE@Index<20
BEGIN
INSERTINTOTEST
SELECT@Index,'kerry';
SET@Index=@Index+1;
END
在会话窗口A中,执行下面SQL语句,模拟一个UPDATE语句正在执行
BEGINTRANSACTION
UPDATEdbo.TESTSETNAME='Kerry'WHEREOBJECT_ID=1;
--ROLLBACK;
会话窗口B中,执行下面的SQL语句
SELECT*FROMdbo.TESTWHEREOBJECT_ID=1
会话窗口C中,执行下面的SQL语句
SELECT*FROMdbo.TESTWHEREOBJECT_ID=1
我实验的场景下,会话窗口A的会话ID为85,会话窗口B的会话ID为90,会话窗口C的会话ID为87,如下所示
如下所示,你会看到SELECT语句“阻塞”了SELECT语句,即会话90“阻塞”了会话87,它们的等待事件都为LCK_M_S,也就是说它们都在等待获取共享锁,也许你会置疑这个SQL是否有问题,那么我们使用SP_WHO来查看,你会发现也是如此,如下所示:
如下所示,我们会发现会话ID为90、87的会话都在等待类型为RID,Resource为1:24171:1的共享锁
其实应该说,会话87、90都在等待RID对象的共享锁,我们知道共享锁与意向共享锁都是兼容的,所以SELECT是不会阻塞SELECT的,那么又怎么解释这个现象呢?在宋大神的指点下,粗略的翻了DatabaseSystemImplementaion这本书(很多原理性知识,看起来相当吃力)。里面介绍了在锁表(locktable)以及ElementInfo、HandlingLockRequests、HandlingUnlocks等概念,有一个有意思的图所示,
在锁表(locktable)里,elementsinfo里的锁的申请是在一个类似队列的结构。先进先出机制,所以当会话90先进入队列,它在等待共享锁(S),会话87也进入队列等待共享锁(S),而且它在会话90的后面(即会话90这个elementsinfo后面的Next指针指向会话87会话的事务),由于两个会话都被阻塞,这两个会话的Wait字段都是Yes,由于内部某些机制,会话87显示阻塞它的会话为90(这个是我个人臆测,实际具体原因有待考究),实质阻塞的源头还是会话85.当会话85释放排它锁(X)后,会话队列根据下面几个原则来处理解锁(HandlingUnlocks):
1:First-come-first-served:Grantthelockrequestthathasbeenwaitingthelongest.Thisstrategyguaranteesnostarvation,thesituationwhereatransactioncanwaitforeverforalock
先来先服务(队列的原则):授予锁等待时间最长的锁请求,这种策略保证不会饿死(翻译感觉不贴切),即一个事务不会永远等待锁的情况。
2.Prioritytosharedlocks:Firstgrantallthesharedlockswaiting.Then,grantoneupdatelock,ifthereareanywaiting.Onlygrantanexclusivelockifnoothersarewaiting.Thisstrategycanallowstarvation,ifatransactioniswaitingforaUorXlock.
共享锁优先,首先授予所有等待共享锁(S),然后授予其中一个更新锁(U),如果有其它类型等待,只有在没有其它锁等待时,才授予排它锁、这一策略允许等待更新锁或排它锁的事务饿死(结束)
3.Prioritytoupgrading:IfthereisatransactionwithaUlockwaitingtoupgradeittoanXlock,grantthatfirst.Otherwise,followoneoftheotherstrategiesmentioned.
锁升级优先,如果有一个持有共享锁(U)等待升级Wie排他锁(X),那么先授予它排它锁,否则采用前面已经提到的策略中的一个。
按照这些原则,当会话85释放了排它锁(X)后,调度器(Scheduler)应该会根据先后顺序依次授予会话90、87共享锁(S),两者的阻塞会几乎同时消失。这个可以也可以通过实验进行一个大概的推断,在上面实验中,你可以手工取消90会话的查询操作,然后再查看阻塞情况,就会发现会话87被85阻塞了。这个阻塞的源头就变成了85,而不是90了。
PS:上面是个人结合一些知识和理解,做的一些肤浅的判断与分析,如果不对的地方,敬请指正!
参考资料:
DatabaseSystemImplementaion
相关文章推荐
- SQL Server实现跨库查询(跨库select insert)
- 最大程度降低 SQL Server 中的阻塞
- Sql Server 函数的操作实例!(执行多条语句,返回Select查询后的临时表)
- Linux 内核机制--阻塞与非阻塞机制及Poll/Select分析
- SQL Server 2017 SELECT…INTO 创建的新表指定到文件组
- SQL Server进程阻塞的检查和解决办法
- 非阻塞select方式解析
- SQL Server推荐使用 SET 而不是 SELECT 对变量进行赋值
- sql server中select语句中取列别名
- sql server中select语句需要申请的锁
- SQL SERVER 2008用Select操作处理数据(四)——Where条件
- 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结
- 如何监视 SQL Server 2000 阻塞[ZT] from MS
- 计算机网络IO:阻塞、非阻塞、同步、异步以及select与epoll
- 【SQL SERVER】如果指定了 SELECT DISTINCT,那么 ORDER BY 子句中的项就必须出现在选择列表中
- [SQL Server 2005/2008] select语句中指定索引
- 如何解决 SQL Server 中的锁升级所致的阻塞问题
- Select单进程非阻塞TCP echo服务器
- Sql Server 中的select(*)和select【字段名】性能的比较