更改或更新表后,row_overflow数据未转换为in_row数据

时间:2017-01-05 07:01:39

标签: sql sql-server

我正在学习Sql server中的分配单元,并了解了3种类型

  • In_row_data LOB_DATA
  • (大对象(LOB)数据)。
  • 行溢出数据。

    IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE
         TABLE_NAME='TEST_ALLOCATION_UNITS')
    
     DROP TABLE TEST_ALLOCATION_UNITS
    CREATE TABLE TEST_ALLOCATION_UNITS(
     TEST_ID INT IDENTITY(1,1)
     ,NAME VARCHAR(4000)
     ,NAME1 VARCHAR(5000)
     )
     GO
    
    INSERT INTO TEST_ALLOCATION_UNITS (NAME,NAME1) VALUES ('APPLE','BANANA')
    GO 500
    

    我在其中插入了500条记录

不,我已经运行了代码,我得到了这样的结果

select s.type_desc before_alter from sys.allocation_units s 
join sys.partitions p on p.partition_id=s.container_id 
where p.object_id=object_id('test_allocation_units')

enter image description here

现在我改变了表并将每个列的大小减少到50个字节,然后再次运行上面的select语句

alter table test_allocation_units alter column name varchar(50)
alter table test_allocation_units alter column name1 varchar(50)

select s.type_desc from sys.allocation_units s 
join sys.partitions p on p.partition_id=s.container_id
where p.object_id=object_id('test_allocation_units')

enter image description here

问题

根据我在更改表之前的理解,该表的列的组合大小大于8 Kb,因此分配类型是In_row_data和Row_overflow_data 。 但是在alter语句之后的 ,即每个列的大小减少到50个字节,那么分配单元仍然是In_row_data和Row_overflow_data

请解释。

提前致谢

场景2

我尝试使用空表并运行以下代码

IF EXISTS (
        SELECT 1
        FROM INFORMATION_SCHEMA.TABLES
        WHERE TABLE_NAME = 'TEST_ALLOCATION_UNITS'
        )
    DROP TABLE TEST_ALLOCATION_UNITS

CREATE TABLE TEST_ALLOCATION_UNITS (
    TEST_ID INT IDENTITY(1, 1)
    ,NAME VARCHAR(4000)
    ,NAME1 VARCHAR(5000)
    )
GO

SELECT s.type_desc before_alter,s.total_pages,s.used_pages,s.data_pages
FROM sys.allocation_units s
JOIN sys.partitions p ON p.partition_id = s.container_id
WHERE p.object_id = object_id('test_allocation_units')

ALTER TABLE test_allocation_units
ALTER COLUMN NAME VARCHAR(50)

ALTER TABLE test_allocation_units
ALTER COLUMN name1 VARCHAR(50)

SELECT s.type_desc after_alter,s.total_pages,s.used_pages,s.data_pages
FROM sys.allocation_units s
JOIN sys.partitions p ON p.partition_id = s.container_id
WHERE p.object_id = object_id('test_allocation_units')

我没有在表格中插入任何记录,上图中的结果显示在图中

enter image description here

请注意为什么即使在更改列大小后,分配单元也没有改变?

2 个答案:

答案 0 :(得分:1)

获取数据"重新分配"你必须运行这个命令:

ALTER TABLE TEST_ALLOCATION_UNITS REBUILD

REBUILD建议SQL Server在HEAP TABLE上重新分配数据页。

答案 1 :(得分:0)

回答你的问题

  

在更改或之后,row_overflow数据未转换为in_row数据   更新表格

,该表从未使用过row_overflow数据,因此在更改列类型时无需转换。

在查询中添加更多列:

select 
    s.type_desc
    ,s.total_pages
    ,s.used_pages
    ,s.data_pages
from 
    sys.allocation_units s 
    join sys.partitions p on p.partition_id=s.container_id 
where 
    p.object_id=object_id('test_allocation_units')

您会看到只有IN_ROW_DATA的页数非零,而ROW_OVERFLOW_DATA有0页保留和使用。

无论如何,当你存储" banana" varchar(5000)列中的值,每行只存储6个字节(加上一些开销)。因此,将此列类型更改为varchar(50)并不会更改数据页中的任何实质内容。

如果列具有char(5000)类型,然后更改为char(50),则表在磁盘上占用的页数会有所不同。当你存储" banana"在char(5000)列中的值,该值右侧填充了4994个空格到列的声明长度,因此此处声明的列大小会立即产生影响。

同样,无论如何,这些空间将存储在行内。如果您尝试创建包含char(4000)char(5000)列的表,则创建将失败,因为SQL Server中的最大行大小为8060字节。

要查看ROW_OVERFLOW_DATA的非零值,您需要在表格的varchar列中存储长字符串。例如:

INSERT INTO TEST_ALLOCATION_UNITS (NAME,NAME1) VALUES 
(REPLICATE('APPLE', 800)
,REPLICATE('BANANA', 833))
GO 500

在这种情况下,我们尝试在name中存储4000个字节,在name1中存储4998个字节,总共8998个(加上一些额外的开销),超过最大8060个字节,所以该值被推离行。

我建议尝试使用短字符串和长字符串添加/删除几行,并检查视图输出的更改方式。这可以帮助您了解视图的结果。