Sql server 标识(主键聚集)表中的间隙是否会影响数据库的性能?
好了,百万美元的问题来了 假设我有下表Sql server 标识(主键聚集)表中的间隙是否会影响数据库的性能?,sql-server,database-design,database-performance,sql-server-2014,database-tuning,Sql Server,Database Design,Database Performance,Sql Server 2014,Database Tuning,好了,百万美元的问题来了 假设我有下表 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[tblUsersProfile]( [personId] [int] IDENTITY(1,1) NOT NULL, [personName] [varchar](16) NOT NULL, [personSurName] [varchar](1
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[tblUsersProfile](
[personId] [int] IDENTITY(1,1) NOT NULL,
[personName] [varchar](16) NOT NULL,
[personSurName] [varchar](16) NOT NULL,
CONSTRAINT [PK_tblUsersProfile] PRIMARY KEY CLUSTERED
(
[personId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
现在让我们假设这个表有200万条记录
因此,下一个标识id
是2000001
但是,我正在进行大规模删除,记录数变为45321
但是,下一个标识id
仍然是2000001
所以用娱乐重新排列桌子会有什么不同
在第一种情况下,将有45321条记录,但标识id将为2000001
在第二种情况下,将再次出现45321条记录,但标识id将为45322
那么,这两种情况之间是否存在性能、存储等方面的差异
多谢各位
SQL Server 2014否。因为它是一个主键数据库引擎,将负责这些记录的物理保存方式。扩展我的评论,进一步解释。为清楚起见,评论是:
不会,不会对性能产生影响。由于这是您的聚类键,因此无论种子是45322还是2000001,记录都将被输入到聚集索引上记录45321之后的下一个可用空间。标识列的值是没有意义的,如果不是,您可能使用不正确。在这样一次大的删除之后,您可能会得到一些索引碎片,但是标识种子与此完全无关 关于碎片,在一个非常简化的示例中,您可能有一个5页的表,每页有100条记录:
- 第1页(ID 1-100)
- 第2页(IDs 101-200)
- 第3页(IDS201-300)
- 第4页(IDS301-400)
- 第5页(IDS401-500)
- 第1页(ID 1、11、21、31、41、51、61、71、81、91)
- 第2页(ID 11111121131141151161171181191)
- 第3页(识别号21、211、221、231、241、251、261、271、281、291)
- 第4页(空)
- 第5页(空)
样本测试代码
-- 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
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
表'DefragTest'。扫描计数1,逻辑读取93(重建前计数)
表'DefragTest'。扫描计数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 52624 7624 98 91 83.78
After Index Rebuild 52624 7624 18 14 544.57
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
表'DefragTest'。扫描计数1,逻辑读取93(重建前计数)
表'DefragTest'。扫描计数1,逻辑读取16(重建后计数)
如您所见,在每种情况下都没有差异,在数据的存储或读取方式上,只有
IDENT_INCR()
的值会发生变化,在这两种情况下,重建聚集索引会大大减少页数,这反过来又提高了查询性能,因为获得相同数据量的逻辑读取更少。否,不会对性能产生影响。由于这是您的聚类键,因此无论种子是45322还是2000001,记录都将被输入到聚集索引上记录45321之后的下一个可用空间。标识列的值是没有意义的,如果不是,您可能使用不正确。在这样一次大的删除之后,您可能会得到一些索引碎片,但标识种子与此完全无关。@GarethD ty for reply所以在索引碎片整理之后,它们应该具有相同的性能,对吗?在索引碎片整理之前,它们将具有相同的性能。在删除一个表的大部分之后,索引碎片整理只是一个值得考虑的问题。@ GarethD这么大删除之后,我想SQL Server物理上将所有剩余的记录重新排序正确吗?尽量不要混淆<代码>主键< /代码>和<代码>聚集索引< /代码>,尽管在这个问题的情况下它们是相同的,数据库负责记录的物理保存方式,因为这是主键,这一说法不正确。这是因为它是集群密钥,而集群密钥恰好也是主键。这是一个重要的区别。