Kra*_*atz 1 performance sql-server clustered-index sql-server-2014
以身份表作为聚簇主键的简单表。我们意外地达到了该列的最大值,因此我要求我们的 DBA 将表重新播种回 0,以便给我们一些时间来检查更新该列。该表也根据时间被清除,所以在我们与任何东西发生碰撞之前,我们有一个很大的 Id 缺口需要用完。由于这是一个高插入表,DBA 提出了页面拆分的可能性,因为我们不再在表的末尾插入。
我的问题是,当标识列的值环绕时,SQL Server 将如何表现?插入间隙会导致性能问题吗?我想考虑创建一个自动循环的序列,而不是将 id 列上升到 bigint。
我的问题是,当标识列的值环绕时,SQL Server 将如何表现?
假设索引是 100% 满的,在新键值处的前几次插入将导致一到两页拆分,其中将整页上的一半行复制到新页,然后将新行插入其中之一半整页。
但是,在那之后,您将恢复低成本插入和页面分配。当页面填满时,会分配一个新的空页面并将其插入到叶页面的双向链表中。没有行被复制到新页,新行被写入新页。
只有这一点,并结束指数的刀片之间的差异是存在下一个页面的新页之后。并且必须使用指向新页面的反向页面指针更新下一页。
有关详细信息,请参阅此帖子:Good Page Splits and Sequential GUID Key Generation
插入间隙会导致性能问题吗?
不。
当 SQL 继续插入索引的“中间”时,当插入的目标页面已满时,SQL 将始终分配一个新页面。它不会将该行放在下一个现有页面上,即使该页面未满。聚集索引的非叶级存储每个叶级页的起始值,因此 SQL 无法在不重写索引的非叶级的情况下将新行插入到下一个现有页中。
您可以通过强制页面锁定并查看插入的锁定占用空间(或使用 DBCC PAGE 不太容易)来轻松查看此行为。在下面的示例中,可以在页面上恰好容纳 4 行的聚集索引表进行了一系列中间索引插入。
假设每页可以容纳 4 行。您有整页现有行,键值从 10-20 升序,现在您要插入键值 1-9。
use master
drop database ps_test
go
create database ps_test
go
use ps_test
go
drop table if exists ps_test
set nocount on
go
--8,060=4*(4+2011)
create table ps_test(id int primary key, data char(2011) not null default '')
go
DBCC TRACEON(3604)
go
insert into ps_test(id) values (10),(11),(12),(13),(14),(15),(16),(17),(18),(19),(20),(21)--,22
go
dbcc ind('ps_test','ps_test',1)
--three data pages
/*
PageFID PagePID PageType
------- ------- / / --------
1 336 10
1 328 1
1 329 2
1 330 1
1 331 1
*/
insert into ps_test(id) values (1)
dbcc ind('ps_test','ps_test',1)
--four data pages 332 has been inserted between 328 and 330
/*
PageFID PagePID PageType PrevPagePID NextPagePID
------- ---------/ / -------- ----------- -----------
1 336 10 0 0
1 328 1 0 332
1 329 2 0 0
1 330 1 332 331
1 331 1 330 0
1 332 1 328 330
*/
dbcc page(ps_test,1,328,3)
-- 328 has rows 1,10 and 4048 bytes free
-- the page is split
/*
PAGE: (1:328)
...
pminlen = 2019 m_slotCnt = 2 m_freeCnt = 4048
...
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 1
...
Slot 1 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 10
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
*/
dbcc page(ps_test,1,332,3)
--page 332 has 11,12,13 and 2024 bytes free
/*
PAGE: (1:332)
...
pminlen = 2019 m_slotCnt = 3 m_freeCnt = 2024
...
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 11
...
Slot 1 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 12
...
Slot 2 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 13
...
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
*/
insert into ps_test(id) values (2)
insert into ps_test(id) values (3)
dbcc ind('ps_test','ps_test',1)
--no page split.
/*
PageFID PagePID PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- -------- ---------- ----------- ----------- ----------- -----------
1 336 10 NULL 0 0 0 0
1 328 1 0 1 332 0 0
1 329 2 1 0 0 0 0
1 330 1 0 1 331 1 332
1 331 1 0 0 0 1 330
1 332 1 0 1 330 1 328
the new rows went on page 328, which now has
pminlen = 2019 m_slotCnt = 4 m_freeCnt = 2024
*/
Run Code Online (Sandbox Code Playgroud)
所以现在我们有第 328 页已满,下一页 332 只有 3 行。但是332上的最低值是11,所以当我们插入值4的时候,会不会继续332,插入5会导致另一个坏页分裂?
insert into ps_test(id) values (4)
dbcc ind('ps_test','ps_test',1)
/*
A new page 333 has been inserted in the list between 328 and 332
PageFID PagePID PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- -------- ---------- ----------- ----------- ----------- -----------
1 336 10 NULL 0 0 0 0
1 328 1 0 1 333 0 0
1 329 2 1 0 0 0 0
1 330 1 0 1 331 1 332
1 331 1 0 0 0 1 330
1 332 1 0 1 330 1 333
1 333 1 0 1 332 1 328
*/
dbcc page(ps_test,1,333,3)
/*
PAGE: (1:333)
...
pminlen = 2019 m_slotCnt = 1 m_freeCnt = 6072
...
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 10
...
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
*/
Run Code Online (Sandbox Code Playgroud)
所以另一个“坏页拆分”,但这个只移动了 id=10 的行。并留下第 328 页完整的值 1,2,3,4
dbcc page(ps_test,1,328,3)
/*
PAGE: (1:328)
...
pminlen = 2019 m_slotCnt = 4 m_freeCnt = 0
...
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 1
...
Slot 1 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 2
...
Slot 2 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 3
...
Slot 3 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 4
...
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
*/
Run Code Online (Sandbox Code Playgroud)
现在所有较大的键值都在单独的页面上,从这里开始,不再有糟糕的页面拆分。下一次插入需要一个新页,并且只有新行在新页上:
insert into ps_test(id) values (5)
dbcc ind('ps_test','ps_test',1)
/*
PageFID PagePID PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
------- ----------- -------- ---------- ----------- ----------- ----------- -----------
1 336 10 NULL 0 0 0 0
1 328 1 0 1 334 0 0
1 329 2 1 0 0 0 0
1 330 1 0 1 331 1 332
1 331 1 0 0 0 1 330
1 332 1 0 1 330 1 333
1 333 1 0 1 332 1 334
1 334 1 0 1 333 1 328
*/
Run Code Online (Sandbox Code Playgroud)
新页面 334,只有最后插入的行。
dbcc page(ps_test,1,334,3)
/*
PAGE: (1:334)
...
pminlen = 2019 m_slotCnt = 1 m_freeCnt = 6072
...
Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4
id = 5
...
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
id = 5
*/
Run Code Online (Sandbox Code Playgroud)
因此,在需要移动行的几个初始“坏页拆分”之后,随后新页被分配并拼接到叶页的双向链接列表的中间。当新行不适合前一页并且没有行迁移到新页时,将分配新页。
| 归档时间: |
|
| 查看次数: |
218 次 |
| 最近记录: |