Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
在日常工作中,我们可能会碰到这种情况,在一个非常繁忙的环境中,尝试进行联机索引操作(Online Index Rebuild)。由于Online Index Rebuild在操作的时候,会申请Sch-M锁来对表的MetaData进行修改。并且,Sch-M锁和很多其他锁不兼容,就有可能会出现阻塞。
比如以下场景,
我们有5个连接,4个Select,1个Alter database rebuild index。51到55依次进入SQL Server执行,下图左边代表了5个连接,右边是SQL内部维护的Lock Queue(这里只是一个很简单的示例,实际的实现会更为复杂)。这里SQL Server维护了两个Queue,Grant Queue存放了所有被赋予了相关Lock的连接。Wait Queue存放了那些等待相关Lock的连接。
首先,51被执行,由于当前表上没有不兼容的锁,所以51获得了所需要的S锁,并且进入了Grant Queue。
接着,在51还在运行的时候,52进来准备运行Rebuild Index Online,但由于Sch-M和S不兼容,所以52会进入Wait Queue等待51完成。
然后,53,54,55依次进入系统执行。由于它们也是Select语句,理论上,和51没有冲突。所以,如果能并行执行的话,可以获得更好的性能。但实际上,在之前版本里,它确是以另一种方式在执行,如下图所示,53,54,55被阻塞在了Wait Queue中。这是因为在之前的实现里,Wait Queue是一个FIFO的实现。当Queue中的第一个语句在等待资源的时候,即使之后的连接所申请的Lock不存在冲突,它也必须等待,直到之前的连接获得所需的资源。
所以,从之前的图示我们可以看到,如果没有52这个连接,51,53,54,55就可以同时执行。而现在由于存在52,导致后进来的3个连接必须在Grant Queue中等待。这个是一种效率低下的实现。
现在,我们来看看SQL 2014中提供的新特性——Managed Lock Priority(MLP)。在MLP中,我们提供了3种不同的选择,如下图所示:
a. Kill all blockers
当执行DDL的时候,如果发现之前有Blocking,DDL会将之前的Blocker终止,然后继续执行。比如,以之前的为例,52会将51终止,然后继续执行。在这里,我们可以通过定义Max_Duration参数来选择等待多少分钟再终止Blocker。
b. Switch to normal queue
这里和上面的区别在于, 在等待Max_Duration之后,如果还没有获得所需要的Lock,它切回到正常的Queue,也就是说,会回到之前的Behavior。
c. Exit DDL after wait
我们也称为“自杀”模式,当Max_Duration到了之后,如果还没有获得所需要的Lock,它会自动退出。
所以,这里我们可以看出,MLP给用户提供了更灵活的选择。如果用户认为Workload更重要,他可以选择“Exit DDL after wait”模式。这样,可以隔一段时间再执行。如果用户认为DDL更重要,可以使用“Kill all blockers”模式。
现在我们来看下在引入MLP后,会发生怎样的变化。这里,我们增加了一个新Queue——Low Priority Queue。
首先,51被执行,由于当前表上没有不兼容的锁,所以51获得了所需要的S锁,并且进入了Grant Queue。
接着,在51还在运行的时候,52进来准备运行Rebuild Index Online,但由于Sch-M和S不兼容,所以52会进入Low Priority Wait Queue等待51完成。
接下来,53,54,55被执行。但现在,它们不会被阻塞在Wait Queue中,所以,它们可以和51被一起执行。等51,53,54,55执行完毕,52被继续执行。这里,我们可以看到这个新的功能可以使得SQL Server在这种情况下获得更好的性能。
接下来,我们来看下,为了实现MLP,SQL语句上增加的新语法。我们增加了两个新的参数(“WAIT_AT_LOW_PRIORITY”和“ABORT_AFTER_WAIT”)来实现对执行的控制。
Alter Table:
<low_priority_lock_wait>::=
{
WAIT_AT_LOW_PRIORITY ( MAX_DURATION = <time> [ MINUTES ], ABORT_AFTER_WAIT = { NONE | SELF | BLOCKERS } )
}
Alter Index:
<low_priority_lock_wait>::=
{
WAIT_AT_LOW_PRIORITY ( MAX_DURATION = <time> [ MINUTES ] ,
ABORT_AFTER_WAIT = { NONE | SELF | BLOCKERS } )
}
最后,需要注意的是,Low Priority Queue只能处理由Partition Switch和Online Rebuild Index所产生的Sch-M lock的请求。对于其他产生的Lock请求,都还会进入正常的Wait Queue中。
这就是今天的分享,更多SQL 2014新功能介绍请持续关注本博客。 下周我们将会介绍SQL 2014备份还原的新特性。








