【问题标题】:row_overflow data was not converting to in_row data after altering or updating the table更改或更新表后,row_overflow 数据未转换为 in_row 数据
【发布时间】:2017-01-05 07:01:39
【问题描述】:

我在学习 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')

现在我更改表并将列大小减少到 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')

问题

根据我在更改表之前的理解,该表的列的组合大小大于 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')

我没有在表中插入任何记录上面脚本的结果如图所示

请告知为什么即使在更改列大小之后分配单元也没有改变?

【问题讨论】:

标签: sql sql-server


【解决方案1】:

要“重新分配”数据,您必须运行以下命令:

ALTER TABLE TEST_ALLOCATION_UNITS REBUILD

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

【讨论】:

  • 真的吗?哪个版本的sql server?
  • sql server 2012
【解决方案2】:

回答你的问题

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 个保留和使用的页。


无论如何,当您在varchar(5000) 列中存储“香蕉”值时,每行仅存储 6 个字节(加上一些开销)。因此,将此列类型更改为 varchar(50) 不会更改数据页中的任何实质性内容。

如果列有char(5000) 类型然后更改为char(50),则该表在磁盘上占用的页数会有所不同。当您在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

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


我建议尝试使用短字符串和长字符串添加/删除几行,并检查视图输出的变化情况。这应该有助于您了解视图的结果。

【讨论】:

  • 我同意你的解释,但你能看看场景2
  • @Smart003,你为什么忽略答案的第一行,我说“在查询中添加更多列:total_pages, used_pages, data_pages”?请这样做并向我们展示结果。我希望在您的方案 2 中,所有类型的页面都将为零,因为该表是空的。 ROW_OVERFLOW_DATA 的 0 used_pages 表示该表没有此类页面。
  • @Smart003,sys.allocation_units 视图返回ROW_OVERFLOW_DATA 类型的行这一事实并不重要。重要的是表格中这种类型的页数。并且视图在您更改列类型之前和之后返回 0 个此类页面。这意味着在您的示例中,有 no 页面具有 ROW_OVERFLOW_DATA 类型。原来没有这样的页面,改变列类型后也没有这样的页面。正如预期的那样。我建议添加/删除带有短字符串和长字符串的行,并检查视图的输出如何变化。
  • 感谢您的解释。我有一些问题 1. 即使更改了列,分配单元(type_desc)也会改变吗? 2.修改列减少到8kb以下后,Sql server会改变分配单元中的类型desc吗?
  • @Smart003, 1. 我希望total_pages, used_pages, data_pages 列中的数字会改变,而不是type_desc 本身。这些数字告诉您表格中每种类型的页数。 2. 它可能不会自动发生。如果在ALTER 之前有非零数量的ROW_OVERFLOW_DATA 页,则可能需要重建表以摆脱它们。自己做实验。用长字符串填充表格并尝试ALTER它。
猜你喜欢
  • 2012-03-09
  • 1970-01-01
  • 2021-11-06
  • 1970-01-01
  • 2021-11-13
  • 2018-07-02
  • 2021-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多