关闭

SQL Server读提交快照隔离级别的注意事项

标签: SQL Server隔离级别
553人阅读 评论(1) 收藏 举报
分类:

前言


当数据库中存在大量面积LCK_M_S 共享锁的时候,我们经常会选择使用读提交快照隔离级别,来解决阻塞的问题.但是所有技术都是使用场景的。在下面的场景下,使用读提交快照,就可能出现错误。

正文


从SQL Server 2005开始,我们就有了READ COMMITTED SNAPSHOT隔离级别(RCSI)和快照隔离级别(SI)。当使用这些新的隔离级别时,SELECT语句在阅读过程中不会获得S共享锁。 (UPDATE,DELETE语句)将他们正在更改的记录的旧版本,存入为TempDb。 他们正在创建一个版本链,其中记录的实际版本(存储在数据库中的数据页面上)指向存储在TempDb页面上的旧版本。 下图显示了这个概念。



为了实现上面的功能,SQL Server必须为数据库中的数据页面上的每个记录添加一个14字节长的指针。 这意味着每个记录的长度将延长14字节。 您可能已经知道,当您使用固定长度的数据类型时,SQL Server中的记录不能超过8060字节。 这意味着启用RCSI / SI可能导致这些记录大于8060字节。 让我们来看一个非常简单的例子
USE master
GO
 
-- Create a new database
CREATE DATABASE VersionStoreRestrictions
GO
 
-- Enable RCSI
ALTER DATABASE VersionStoreRestrictions SET READ_COMMITTED_SNAPSHOT ON
GO
 
-- Use it
USE VersionStoreRestrictions
GO
 
-- Create a table where each record is 8047 bytes large
CREATE TABLE TableB
(
   Column1 CHAR(40),
   Column2 CHAR(8000)
)
GO



从前面的代码中可以看到,我创建了一个表CHAR类型,加起来长度为8040字节。对于每个记录,SQL Server内部需要至少7个字节的开销。在这种情况下,一行记录需要8047字节的数据页。因为我们在数据库级别上启用了RCSI,所以SQL Server必须为行版本指针添加额外的14个字节,将表中的每个记录扩展到8061个字节。这意味着每个记录对都会超出SQL Server 规定的8060 (1 byte)
首先,我们将一个记录插入到表格中
-- Insert a initial row
INSERT INTO TableB VALUES (REPLICATE('A', 40), REPLICATE('A', 8000))
GO




然后,执行下面的update
UPDATE TableB
SET Column1 = REPLICATE('B', 40)
GO
Msg682,Level22,State214,Line2
Internalerror.Bufferprovidedtoreadcolumnvalueistoosmall.RunDBCCCHECKDBtocheckforanycorruption.

是一个内部错误,因为SQL Server使用的缓冲区只有8060字节大,现在我们尝试存储在缓冲区8061字节 - SQL Server 2008上还可以重现。 有趣的是,SQL Server Denali CTP1(就是SQL Server 2012)已经修复了这个错误,其中页面转储显示SQL Server存储预期的8061字节。
当您为现有数据库启用RCSI / SI时,请记住这个错误,因为这意味着RCSI / SI不是在任何场景都适用。 当您的数据库中有一个超过8046字节限制的表格时,您将遇到真正的麻烦

总结

除了上述问题,读提交快照还会增加tempdb的压力。这也是需要考虑的一个因素。

2
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:30624次
    • 积分:854
    • 等级:
    • 排名:千里之外
    • 原创:47篇
    • 转载:4篇
    • 译文:1篇
    • 评论:16条
    博客专栏
    最新评论