SQL Server 2014如何提升非在线的在线操作
2015-07-07 08:05
525 查看
在今天的文章里,我想谈下[b]在线索引重建操作( Online Index Rebuild operations)[/b],它们在SQL Server 2014里有怎样的提升。我们都知道,自SQL Server 2005开始引入了在线索引重建操作。但这些在线操作并非真正的在线操作,因为在操作开始时,SQL Server需要获得共享表锁(Shared Table Lock (S) ),在操作结束时需要在对应表上获得架构修改锁(Schema Modification Lock (Sch-M) )。因此这些操作是真正的在线操作,只是营销技巧(marketing trick)。但是,亲,“在线”肯定比“部分在线”好听多了。
尽管如此,SQL Server 2014还是在在线索引重建的开始和结束发生的阻塞做了一些改进。因此,在你执行在线索引重建时,你可以定义所谓的[b]锁优先级(Lock Priority)[/b]。来看看下面的代码,你会看到起作用的新语法:
当阻塞情况发生时,你可以用[b]WAIT_AT_LOW_PRIORITY[/b]关键字定义如何处理。使用第1个属性[b]MAX_DURATION[/b]指定你想要等待的时间——这里是分钟,不是秒!用[b]ABORT_AFTER_WAIT[/b]属性你指定哪个会话需要被SQL Server回滚。[b]SELF[/b]意味着那个ALTER INDEX REBUILD语句会回滚,当你指定[b]BLOCKERS[/b]时,阻塞的会话会回滚。当然,当没有阻塞发生时,在线索引重建操作会立即执行。因此这里你只能配置当阻塞情况发生时要怎么处理。
好了,我们来实操下。我们新建一个数据库,一个简单的表和一个聚集索引。
为了触发阻塞,我在不同的会话开始一个新的事务,但不提交:
这意味着我们在需要修改的记录上获得[b]排它锁(Exclusive Lock (X))[/b],在对应的页上获得[b]意向排它锁(Intent-Exclusive Lock (IX))[/b],在表本身获得[b]意向排它锁(Intent-Exclusive Lock (IX))[/b]。我们刚刚在SQL Server里创建了典型的锁定层次(locking hierarchy):表=>页=>记录。在表级别的意向排它锁(IX Lock)和在线索引重建操作需要的共享锁(Shared Lock)是不兼容的——典型的锁/阻塞情形发生了。当你现在执行在线索引重建操作时,会发生阻塞:
当你查看DMV sys.dm_tran_locks时,你会看到那个需要共享锁(Shared Lock(S))的会话需要等待。这个会话会永远等待。我刚才就说过:“部分在线”……
当我们执行带有锁优先级(Lock Priority)的在线索引重建时,有趣的事情发生了:
在这个情况下,我们的[b]ALTER INDEX[/b]语句会等待1分钟([b]MAX_DURATION[/b]),然后语句本身取消了([b]ABORT_AFTER_WAIT[/b])。
如果你在这里指定了[b]BLOCKERS[/b]选项,那么阻塞的会话就会回滚。当我们同时(在1分钟期间)查看DMV [b]sys.dm_tran_locks[/b],我们看到了有趣的东西:
从图中可以看到,SQL Server这里请求一个[b]LOW_PRIORITY_WAIT[/b]的状态。因此3个请求状态([b]GRANT,WAIT,CONVERT[/b])有了第4个选项:[b]LOW_PRIORITY_WAIT[/b]。当我们查看DMV [b]sys.dm_os_waiting_tasks[/b]时,事情变得有意思(59是执行语句的会话ID):
在线索引重建操作的等待会话报告了一个新的等待类型[b]LCK_M_S_LOW_PRIORITY[/b]。这意味着当在线索引重建操作被阻塞时,我们可以从服务器级别([b]sys.dm_os_wait_stats[/b])的等待统计信息里获得——不错!
但是[b]LCK_M_S_LOW_PRIORITY[/b]并不是新的等待类型。在SQL Server 2014里,当你查看DMV [b]sys.dm_os_wait_stats[/b]时,会看到21个新的等待类型:
LCK_M_SCH_S_LOW_PRIORITY
LCK_M_SCH_M_LOW_PRIORITY
LCK_M_S_LOW_PRIORITY
LCK_M_U_LOW_PRIORITY
LCK_M_X_LOW_PRIORITY
LCK_M_IS_LOW_PRIORITY
LCK_M_IU_LOW_PRIORITY
LCK_M_IX_LOW_PRIORITY
LCK_M_SIU_LOW_PRIORITY
LCK_M_SIX_LOW_PRIORITY
LCK_M_UIX_LOW_PRIORITY
LCK_M_BU_LOW_PRIORITY
LCK_M_RS_S_LOW_PRIORITY
LCK_M_RS_U_LOW_PRIORITY
LCK_M_RIn_NL_LOW_PRIORITY
LCK_M_RIn_S_LOW_PRIORITY
LCK_M_RIn_U_LOW_PRIORITY
LCK_M_RIn_X_LOW_PRIORITY
LCK_M_RX_S_LOW_PRIORITY
LCK_M_RX_U_LOW_PRIORITY
LCK_M_RX_X_LOW_PRIORITY
所有主要的等待类型(LCK_M_*)都有额外的锁优先级等待类型。这个非常酷,也非常强大,因为你很容易从中可以跟踪到为什么在线重建索引操作被阻塞。另外,对于分区切换(Partition Switching)也适用同样的技术(锁优先级(Lock Priorities)),因为在切换期间,操作也要在2个表(原表,目标表)上获取架构修改锁(Schema Modification Lock (Sch-M))。
我希望这篇文章可以让你理解SQL Server 2014里的锁优先级(Lock Priorities),还有为什么SQL Server里的“在线”操作实际上只是“部分在线”。
感谢关注!
尽管如此,SQL Server 2014还是在在线索引重建的开始和结束发生的阻塞做了一些改进。因此,在你执行在线索引重建时,你可以定义所谓的[b]锁优先级(Lock Priority)[/b]。来看看下面的代码,你会看到起作用的新语法:
ALTER INDEX idx_Col1 ON Foo REBUILD WITH ( ONLINE = ON ( WAIT_AT_LOW_PRIORITY ( MAX_DURATION = 1, ABORT_AFTER_WAIT = SELF ) ) ) GO
当阻塞情况发生时,你可以用[b]WAIT_AT_LOW_PRIORITY[/b]关键字定义如何处理。使用第1个属性[b]MAX_DURATION[/b]指定你想要等待的时间——这里是分钟,不是秒!用[b]ABORT_AFTER_WAIT[/b]属性你指定哪个会话需要被SQL Server回滚。[b]SELF[/b]意味着那个ALTER INDEX REBUILD语句会回滚,当你指定[b]BLOCKERS[/b]时,阻塞的会话会回滚。当然,当没有阻塞发生时,在线索引重建操作会立即执行。因此这里你只能配置当阻塞情况发生时要怎么处理。
好了,我们来实操下。我们新建一个数据库,一个简单的表和一个聚集索引。
-- Creates a new database CREATE DATABASE Test GO -- Use the database USE Test GO -- Create a simple table CREATE TABLE Foo ( Col1 INT IDENTITY(1, 1) NOT NULL, Col2 INT NOT NULL, Col3 INT NOT NULL ) GO -- Create a unique Clustered Index on the table CREATE UNIQUE CLUSTERED INDEX idx_Col1 ON Foo(Col1) GO -- Insert a few test records INSERT INTO Foo VALUES (1, 1), (2, 2), (3, 3) GO
为了触发阻塞,我在不同的会话开始一个新的事务,但不提交:
BEGIN TRANSACTION UPDATE Foo SET Col2 = 2 WHERE Col1 = 1
这意味着我们在需要修改的记录上获得[b]排它锁(Exclusive Lock (X))[/b],在对应的页上获得[b]意向排它锁(Intent-Exclusive Lock (IX))[/b],在表本身获得[b]意向排它锁(Intent-Exclusive Lock (IX))[/b]。我们刚刚在SQL Server里创建了典型的锁定层次(locking hierarchy):表=>页=>记录。在表级别的意向排它锁(IX Lock)和在线索引重建操作需要的共享锁(Shared Lock)是不兼容的——典型的锁/阻塞情形发生了。当你现在执行在线索引重建操作时,会发生阻塞:
ALTER INDEX idx_Col1 ON Foo REBUILD WITH ( ONLINE = ON ) GO
当你查看DMV sys.dm_tran_locks时,你会看到那个需要共享锁(Shared Lock(S))的会话需要等待。这个会话会永远等待。我刚才就说过:“部分在线”……
SELECT * FROM sys.dm_tran_locks
当我们执行带有锁优先级(Lock Priority)的在线索引重建时,有趣的事情发生了:
-- Perform an Online Index Rebuild ALTER INDEX idx_Col1 ON Foo REBUILD WITH ( ONLINE = ON ( WAIT_AT_LOW_PRIORITY ( MAX_DURATION = 1, ABORT_AFTER_WAIT = SELF ) ) ) GO
在这个情况下,我们的[b]ALTER INDEX[/b]语句会等待1分钟([b]MAX_DURATION[/b]),然后语句本身取消了([b]ABORT_AFTER_WAIT[/b])。
如果你在这里指定了[b]BLOCKERS[/b]选项,那么阻塞的会话就会回滚。当我们同时(在1分钟期间)查看DMV [b]sys.dm_tran_locks[/b],我们看到了有趣的东西:
从图中可以看到,SQL Server这里请求一个[b]LOW_PRIORITY_WAIT[/b]的状态。因此3个请求状态([b]GRANT,WAIT,CONVERT[/b])有了第4个选项:[b]LOW_PRIORITY_WAIT[/b]。当我们查看DMV [b]sys.dm_os_waiting_tasks[/b]时,事情变得有意思(59是执行语句的会话ID):
SELECT * FROM sys.dm_os_waiting_tasks WHERE session_id='59'
在线索引重建操作的等待会话报告了一个新的等待类型[b]LCK_M_S_LOW_PRIORITY[/b]。这意味着当在线索引重建操作被阻塞时,我们可以从服务器级别([b]sys.dm_os_wait_stats[/b])的等待统计信息里获得——不错!
但是[b]LCK_M_S_LOW_PRIORITY[/b]并不是新的等待类型。在SQL Server 2014里,当你查看DMV [b]sys.dm_os_wait_stats[/b]时,会看到21个新的等待类型:
SELECT * FROM sys.dm_os_wait_stats WHERE wait_type LIKE '%LOW_PRIORITY%'
LCK_M_SCH_S_LOW_PRIORITY
LCK_M_SCH_M_LOW_PRIORITY
LCK_M_S_LOW_PRIORITY
LCK_M_U_LOW_PRIORITY
LCK_M_X_LOW_PRIORITY
LCK_M_IS_LOW_PRIORITY
LCK_M_IU_LOW_PRIORITY
LCK_M_IX_LOW_PRIORITY
LCK_M_SIU_LOW_PRIORITY
LCK_M_SIX_LOW_PRIORITY
LCK_M_UIX_LOW_PRIORITY
LCK_M_BU_LOW_PRIORITY
LCK_M_RS_S_LOW_PRIORITY
LCK_M_RS_U_LOW_PRIORITY
LCK_M_RIn_NL_LOW_PRIORITY
LCK_M_RIn_S_LOW_PRIORITY
LCK_M_RIn_U_LOW_PRIORITY
LCK_M_RIn_X_LOW_PRIORITY
LCK_M_RX_S_LOW_PRIORITY
LCK_M_RX_U_LOW_PRIORITY
LCK_M_RX_X_LOW_PRIORITY
所有主要的等待类型(LCK_M_*)都有额外的锁优先级等待类型。这个非常酷,也非常强大,因为你很容易从中可以跟踪到为什么在线重建索引操作被阻塞。另外,对于分区切换(Partition Switching)也适用同样的技术(锁优先级(Lock Priorities)),因为在切换期间,操作也要在2个表(原表,目标表)上获取架构修改锁(Schema Modification Lock (Sch-M))。
我希望这篇文章可以让你理解SQL Server 2014里的锁优先级(Lock Priorities),还有为什么SQL Server里的“在线”操作实际上只是“部分在线”。
感谢关注!
参考文章:
https://www.sqlpassion.at/archive/2014/01/02/how-sql-server-2014-improves-online-operations-that-arent-online-operations/相关文章推荐
- Oracle数据库中的分页--rownum
- Mysql子查询,连接,多表更新
- MySQL创建用户及权限控制
- Introduction to Locking in SQL Server
- SQLAlchemy使用笔记
- Oracle 11g ORA-12514:TNS:监听程序当前无法识别连接描述符中请求的服务
- ehcache memcache redis 三大缓存男高音
- 学习MongoDB 二:MongoDB添加、删除、修改
- python操作redis的方法
- MongoDB运行状态监控、性能分析工具mongostat详解
- SQL Server存储过程中使用表值作为输入参数示例
- SQL Server自定义异常raiserror使用示例
- SqlServer中查看当前Open的Cursor方法
- 查询SQLServer启动时间的三种方法
- SQL语句实现查询SQL Server服务器名称和IP地址
- SQL语句实现查询SQL Server内存使用状况
- SQL语句实现查询Index使用状况
- SQL语句实现查询并自动创建Missing Index
- SQL语句实现查询当前数据库IO等待状况
- 详解MySQL中的外键约束问题