• 对于大于8046 bytes的行,RCSI/SI事务隔离级别无效


    自SQL Server 2005起,我们有了READ COMMITTED SNAPSHOT ISOLATION level (RCSI) 和SNAPSHOT ISOLATION level (SI)两个事务隔离级别。当你使用这些事务隔离级别时,读操作(SELECT语句)在读的时候不需要S锁(共享锁),写操作(UPDATE,DELETE语句)会对记录进行版本控制,这些改变会写入TempDb。它们就会生成一个版本链,记录的最新版本(存在数据库里的数据页里)指向存在TempDb里的页,下图可以帮助我们理解这个情况。

    为了使这个机制有效,SQL Server需要在数据库内部的数据页上的每条记录,增加14 bytes长的指针。这就是说,每条记录增加了14 bytes的长度。或许你已经知道,当你使用定长数据类型时,SQL Server内部的记录长度不能超过8060 bytes。这就意味着,当你启用RCSI/SI隔离级别时,会导致记录超过现有的8060 bytes。我们来看一个简单的例子:

     1 USE master
     2 GO
     3 
     4 -- Create a new database
     5 CREATE DATABASE VersionStoreRestrictions
     6 GO
     7 
     8 -- Enable RCSI
     9 ALTER DATABASE VersionStoreRestrictions SET READ_COMMITTED_SNAPSHOT ON
    10 GO
    11 
    12 -- Use it
    13 USE VersionStoreRestrictions
    14 GO
    15 
    16 -- Create a table where each record is 8047 bytes large
    17 CREATE TABLE TableB
    18 (
    19    Column1 CHAR(40),
    20    Column2 CHAR(8000)
    21 )
    22 GO

    从代码里我们可以看到,这里我创建了带2个CHAR列,总长为8040 bytes的表。SQL Server为每条记录内部需要至少7 bytes的开销。这里数据页上的1条记录需要8047 bytes。因为我们在数据库级别启用了RCSI数据隔离级别,SQL Server需要增加额外的14 bytes作为行版本指针(Row Version Pointe),这就把表里的每条记录长度扩展到8061 bytes。对于SQL Server来说,这就意味着每条记录太长了(多出1 byte)。我们在表里插入1条记录看看:

    1 -- Insert a initial row
    2 INSERT INTO TableB VALUES (REPLICATE('A', 40), REPLICATE('A', 8000))
    3 GO

    现在当你尝试去更新这个记录(SQL Server尝试在TempDb里对这条记录进行版本控制),SQL Server会报下列错误:

    1 UPDATE TableB
    2 SET Column1 = REPLICATE('B', 40)
    3 GO

    这个错误信息非常有意义,因为数据库上下文信息是错误的(SSMS显示你还在master数据库)。但是当你在UPDATE语句加上表架构时,你就能拿回实际的错误信息:

    1 UPDATE VersionStoreRestrictions.dbo.TableB
    2 SET Column1 = REPLICATE('B', 40)
    3 GO
    4  

    哇噢,这是个内部错误,因为SQL Server使用的缓存只有8060 bytes 大,现在我们尝试在那个缓存里保存8061 bytes——瞧!这在SQL Server内部是个bug!你可以在自SQL SERVER 2005以后的版本里验证这个BUG,也就说,这个BUG已经存在好几年了(SQL Server 2012已经修正这个BUG,但在页里面的确存储了预期的8061 bytes,我测试的版本是SQL Server 2008R2)。

    当你对数据库启用RCSI/SI数据隔离级别时,你就要留意这个BUG了,因为这意味这RCSI/SI在任何情况下都无效了。当在你的数据库里有1个表超过8046 bytes限制,那你真的是有麻烦了!通过这个危险的BUG(nasty bug),你也会理解,知道SQL Serve内部架构和内部如何存储数据是多么重要!! 

    参考文章:

    https://www.sqlpassion.at/archive/2011/05/06/rcsisi-doesnt-work-with-rows-larger-than-8046-bytes/

  • 相关阅读:
    JavaScript的学习----2.操作BOM对象
    Maven的配置和Eclipse中导入SpringBoot项目一些注意点
    JavaScript学习----1.基础篇
    线程池的学习
    CSS的初步学习
    类的加载细节探索
    反射与注解
    数据结构第二章
    数据结构第一章
    用结构和STL常用算法实现对学生成绩的排序和查找(vector)
  • 原文地址:https://www.cnblogs.com/woodytu/p/4578564.html
Copyright © 2020-2023  润新知