页面拆分?这个怎么运作?

时间:2018-04-21 15:31:34

标签: sql sql-server

  1. 页面拆分是否会影响索引或表中的数据的物理排序?示例:如果您有一个索引的电子邮件列,并且页面拆分发生了很多,那么所列出的电子邮件是否会在列表中出现故障,现在更长时间了?

  2. 页面拆分/碎片如何与删除主键记录一起使用?示例:如果您有下表,主键是数字。

    1, bob, chair
    2, joe, table
    3, brandon, lamp
    4, jared, tv
    
  3. 让我们说你删除记录3.现在表读取1,2,4(乱序),然后记录3在以后重新插入?然后它将读1,2,4,3。记录4是否占用记录3的空间,或者是否在以后重新插入记录3的情况下保留?或者您是否必须执行索引重建以对其进行物理重新排序?

    谢谢

3 个答案:

答案 0 :(得分:0)

SQL Server使用聚簇索引表(默认情况下)。这些表按主键排序。

插入中间值时,页面会重新排列,以便为新行分配空间。据我了解,当你删除一行后,空间将被回收(在某些时候)。这些操作执行起来很昂贵。

这就是为什么通常建议使用主键的自动递增值,以避免您提到的问题。

答案 1 :(得分:0)

1。)聚簇索引是一个非物理的逻辑顺序,避免试图将其视为一个真实的物理顺序,索引和存储之间有太多的抽象层次来考虑物理顺序。 (范围分配,文件组,磁盘/ Lun上的碎片,Lun'它们本身 - 所有这些都使得物理订单的概念不正确。)

以维护逻辑顺序的方式处理页面拆分,更新表格的正向/反向双链表链接页面,以便将新页面插入到'顺序'可以这么说。

2。)物理顺序与逻辑 - 再次,只是停止考虑物理排序,即使行在同一页面上,页面的插槽数组也是维护页面本身数据实际顺序的数组。因此,在页面上它可能最终为1,2,4,3,插槽阵列将为4,3,2,1(插槽阵列从页面末尾开始并向后读取) - 是否空间重新开始 - 使用与否并不重要,因为它将处理页面上的偏移位置与通过该阵列维护的顺序。

Impaler提到使用主键的自动增量值 - 主键和群集键不必是同一个东西,而我同意您经常使用身份字段作为群集密钥 - 主要密钥密钥应根据需要和可用的候选密钥单独考虑。

SQL Server如何在存储级别工作可能会涉及一个非常复杂的主题,我个人会推荐Kalen Delaney的书,尽管其他人都可以使用。

答案 2 :(得分:0)

让我们来看看你的例子,看看会发生什么。

首先,虚拟表和虚拟数据。

CREATE TABLE testing (ID INT PRIMARY KEY, junk VARCHAR(100))
GO 

INSERT INTO testing(ID, junk)
VALUES 
(1, 'blah'),
(2, 'blahhhh'),
(3, 'Blabbb')
GO 

现在,让我们看看存储它的实际数据页。

SELECT
   *, 
   sys.fn_PhysLocFormatter(%%physloc%%) AS Page_Location
   from testing

获取该函数的输出并将其放入DBCC PAGE

DBCC TRACEON(3604) --Send output of DBCC PAGE to SSMS Client
GO
DBCC PAGE('your_db_name',the_first_num_from_page_location,the_second_num_from_page_location,3)

这将显示数据页面实际上具有的内容。 “Slots”是表格中的行,页面从Slot 0开始。

Slot 0 Offset 0x60 Length 19

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP VARIABLE_COLUMNS
Record Size = 19                    
Memory Dump @0x0000004493BFA060

0000000000000000:   30000800 01000000 02000001 00130062 6c6168    0..............blah

Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4

ID = 1                              

Slot 0 Column 2 Offset 0xf Length 4 Length (physical) 4

junk = blah                         

Slot 0 Offset 0x0 Length 0 Length (physical) 0

KeyHashValue = (8194443284a0)   

继续阅读页面,您将看到3行数据。现在,删除记录2并重新运行page_location查询并在页面上查看。插槽1现在应该是您的ID = 3记录。

DELETE FROM testing
WHERE ID = 2

现在,重建您的PK索引并重新插入记录2.

ALTER INDEX your_pk here ON testing
REBUILD

INSERT INTO testing(ID, Junk)
VALUES 
(2,'blerg')
GO 

重新运行page_location查询,因为重建后页面可能已更改并查看您的插槽。即使您在3之后插入2,插槽1(第2行)也是您的ID = 2记录。

但是,数据页上有一个称为Slot Array的东西,它存储了数据的逻辑顺序。因此,即使页面上的数据可能完全无序地物理存储,插槽阵列也会告诉sql server如何根据索引对其进行逻辑排序。

你可以在这里看到这个:

DBCC TRACEON(3604) --Send output of DBCC PAGE to SSMS Client
GO
DBCC PAGE('your_db_name',the_first_num_from_page_location,the_second_num_from_page_location,2)

在最底部,您将看到偏移表: OFFSET表:

Row - Offset                        
2 (0x2) - 115 (0x73)                
1 (0x1) - 136 (0x88)                
0 (0x0) - 96 (0x60)   

再次重建PK,看看它是如何变化的:

OFFSET TABLE:

Row - Offset                        
2 (0x2) - 135 (0x87)                
1 (0x1) - 115 (0x73)                
0 (0x0) - 96 (0x60)   

因此,页面上的数据可能完全是物理上的乱序,但是插槽数组会根据您的索引定义告诉引擎它应该处于哪个顺序。您在SSMS或数据页面上的结果可能看起来是按物理排序的顺序,但实际上它可能完全不同,并且插槽阵列正在跟踪它应该处于什么顺序。重新插入PK行无序可能肯定会导致页面拆分,如果它必须推送数据。