扩展我的评论以进一步解释。为清楚起见,评论是:
不,不会对性能产生影响。由于这是您的集群键,无论种子是 45,322 还是 2,000,0001,记录仍将输入到记录 45,321 之后的集群索引上的下一个可用空间。Identity 列的值是没有意义的,如果不是,您可能没有正确使用。在像这样的大删除之后,您可能最终会出现一些索引碎片,但身份种子与此完全无关。
关于碎片,在一个非常简化的示例中,您可能有一个有 5 页的表,每页有 100 条记录:
- 第 1 页(ID 1 - 100)
- 第 2 页(ID 101 - 200)
- 第 3 页(ID 201 - 300)
- 第 4 页(ID 301 - 400)
- 第 5 页(ID 401 - 500)
现在,如果您进行删除,并删除最后一位不是 1 的所有记录,以及 ID 超过 300 的所有记录,您会得到:
- 第 1 页(ID 1、11、21、31、41、51、61、71、81、91)
- 第 2 页(ID 11、111、121、131、141、151、161、171、181、191)
- 第 3 页(ID 21、211、221、231、241、251、261、271、281、291)
- 第 4 页(空)
- 第 5 页(空)
当我们现在插入这个表时,无论下一个标识是 291 还是 501,它都不会改变任何东西。页面必须保持正确的顺序,因此最高 ID 为 291,因此必须在之后插入下一条记录,如果有空间,则在同一页面上,否则创建新页面。在这种情况下,第 3 页上有 9 个空槽,因此可以在那里插入下一条记录。由于 292 和 500 都高于 291,因此行为是相同的。
在这两种情况下,问题仍然存在,删除后您有 3 个页面有大量可用空间(只有 10% 已满),您现在只有 30 条记录,这些记录很适合一页,因此您可以重建索引来执行此操作,所以现在您只需要阅读一个页面即可获取所有数据。
我再次强调,这是一个非常简单的示例,我不建议重建聚集索引来释放 2 页!
同样重要的是要强调这种行为是因为 ID 列是集群键,而不是主键。它们不一定是相同的,但是,如果您在身份列以外的其他内容上进行聚类,那么在删除后是否重新设置种子对性能仍然没有影响。标识列的存在纯粹是为了标识,只要您可以唯一标识一行,实际值就无关紧要。
示例测试代码
-- CREATE TABLE AND FILL WITH 100,000 ROWS
IF OBJECT_ID(N'dbo.DefragTest', 'U') IS NOT NULL
DROP TABLE dbo.DefragTest;
CREATE TABLE dbo.DefragTest (ID INT IDENTITY(1, 1) PRIMARY KEY, Filler CHAR(1) NULL);
INSERT dbo.DefragTest (Filler)
SELECT TOP 100000 NULL
FROM sys.all_objects AS a, sys.all_objects AS b;
-- CHECK PAGE STATISTICS
SELECT Stage = 'After Initial Insert',
IdentitySeed = IDENT_CURRENT(N'dbo.DefragTest'),
p.rows,
a.total_pages,
a.data_pages,
AvgRecordsPerPage = CAST(p.rows / CAST(a.data_pages AS FLOAT) AS DECIMAL(10, 2))
FROM sys.partitions AS p
LEFT JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID(N'dbo.DefragTest', 'U')
AND p.index_id IN (0, 1); -- CLUSTERED OR HEAP
-- DELETE RECORDS
DELETE dbo.DefragTest
WHERE ID % 10 != 1
OR ID > 50000;
-- CHECK PAGE STATISTICS
SELECT Stage = 'After Delete',
IdentitySeed = IDENT_CURRENT(N'dbo.DefragTest'),
p.rows,
a.total_pages,
a.data_pages,
AvgRecordsPerPage = CAST(p.rows / CAST(a.data_pages AS FLOAT) AS DECIMAL(10, 2))
FROM sys.partitions AS p
LEFT JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID(N'dbo.DefragTest', 'U')
AND p.index_id IN (0, 1); -- CLUSTERED OR HEAP
-- RESEED (REMOVED FOR ONE RUN)
DBCC CHECKIDENT ('dbo.DefragTest', RESEED, 50000);
--INSERT ROWS TO SEE EFFECT ON PAGE
INSERT dbo.DefragTest (Filler)
SELECT TOP 10000 NULL
FROM sys.all_objects AS a;
-- CHECK PAGE STATISTICS
SELECT Stage = 'After Second Insert',
IdentitySeed = IDENT_CURRENT(N'dbo.DefragTest'),
p.rows,
a.total_pages,
a.data_pages,
AvgRecordsPerPage = CAST(p.rows / CAST(a.data_pages AS FLOAT) AS DECIMAL(10, 2))
FROM sys.partitions AS p
LEFT JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID(N'dbo.DefragTest', 'U')
AND p.index_id IN (0, 1); -- CLUSTERED OR HEAP
-- CHECK READS REQUIRED FOR FULL TABLE SCAN
SET STATISTICS IO ON;
SELECT COUNT(Filler)
FROM dbo.DefragTest;
-- REBUILD INDEX
ALTER INDEX PK_DefragTest__ID ON dbo.DefragTest REBUILD;
-- CHECK PAGE STATISTICS
SELECT Stage = 'After Index Rebuild',
IdentitySeed = IDENT_CURRENT(N'dbo.DefragTest'),
p.rows,
a.total_pages,
a.data_pages,
AvgRecordsPerPage = CAST(p.rows / CAST(a.data_pages AS FLOAT) AS DECIMAL(10, 2))
FROM sys.partitions AS p
LEFT JOIN sys.allocation_units AS a
ON a.container_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID(N'dbo.DefragTest', 'U')
AND p.index_id IN (0, 1); -- CLUSTERED OR HEAP
-- CHECK READS REQUIRED FOR FULL TABLE SCAN
SELECT COUNT(Filler)
FROM dbo.DefragTest;
SET STATISTICS IO OFF;
带种子的输出:
Stage IdentitySeed rows total_pages data_pages AvgRecordsPerPage
After Initial Insert 100000 100000 178 174 574.71
After Delete 100000 5000 90 87 57.47
After Second Insert 52624 7624 98 91 83.78
After Index Rebuild 52624 7624 18 14 544.57
表“碎片整理测试”。扫描计数 1,逻辑读取 93 (重建前计数)
表“碎片整理测试”。扫描计数 1,逻辑读取 16 (重建后计数)
无种子输出:
Stage IdentitySeed rows total_pages data_pages AvgRecordsPerPage
After Initial Insert 100000 100000 178 174 574.71
After Delete 100000 5000 90 87 57.47
After Second Insert 102624 7624 98 91 83.78
After Index Rebuild 52624 7624 18 14 544.57
表“碎片整理测试”。扫描计数 1,逻辑读取 93 (重建前计数)
表“碎片整理测试”。扫描计数 1,逻辑读取 16 (重建后计数)
如您所见,在每种情况下都没有区别,在存储或读取数据的方式上IDENT_INCR()
,变化的只是值,并且在这两种情况下,重建聚集索引都大大减少了页面数量,这反过来又提高查询性能,因为获得相同数据量的逻辑读取更少。