我知道,索引碎片的一些原因是:
非顺序插入 - 在执行非顺序插入时,SQL Server将大约50%的数据从旧页面移动到新分配的页面。这将导致页面拆分,每个页面都有来自旧页面的大约50%的数据。
使用较大的值更新现有行值,该值不适合同一页面
我听说即使您回滚事务,碎片仍然存在,但我找不到相关文档。
是否有人有这方面的文件或证明这一点的脚本?
答案 0 :(得分:0)
今天我做了一些测试,结果并不完全符合我的预期。
环境:
Microsoft SQL Server 2008(SP2) - 10.0.4000.0(X64)2010年9月16日19:43:16版权所有(c)1988-2008 Microsoft Corporation企业版(64位)在Windows NT 6.0上(Build 6002:Service)包2)
首先,我找了一张已经碎片的表。 令人惊讶的是,在我的DBA数据库中,我找到了一个名为tableSizeBenchmark的表。
USE [DBA]
GO
CREATE TABLE [dbo].[tableSizeBenchmark](
[lngID] [bigint] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[dbName] [varchar](100) NOT NULL,
[tableName] [varchar](100) NOT NULL,
[creationDate] [smalldatetime] NOT NULL,
[numberOfRows] [bigint] NULL,
[spaceUsedMb] [numeric](18, 0) NULL,
CONSTRAINT [PK_tableSizeBenchmark] PRIMARY KEY CLUSTERED
(
[lngID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
ON [PRIMARY]
) ON [PRIMARY]
GO
USE [DBA]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UIXtableSizeBenchmark] ON [dbo].[tableSizeBenchmark]
(
[dbName] ASC,
[tableName] ASC,
[creationDate] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
这是在进行任何测试之前的碎片级别:
您需要创建这两个程序才能进行相同的测试。 基本上我使用随机字符串生成器和随机数生成器,只是因为我想插入10,000条记录并查看如何使碎片变得更糟,稍后在ROLLBACK事务中看到真实,如果碎片仍然存在或消失。
--DROP PROCEDURE GetRandomString
--GO
--DROP PROCEDURE GetRandomNumber
--GO
create procedure GetRandomString (@STR VARCHAR(100) OUTPUT)
as
begin
-- generates a random string
-- marcelo miorelli
-- 01-oct-2014
-- one of the other features that makes this more flexible:
-- By repeating blocks of characters in @CharPool,
-- you can increase the weighting on certain characters so that they are more likely to be chosen.
DECLARE @z INT
, @i INT
, @MIN_LENGTH INT
, @MAX_LENGTH INT
DECLARE @CharPool VARCHAR(255)
DECLARE @RandomString VARCHAR(255)
DECLARE @PoolLength INT
SELECT @MIN_LENGTH = 20
SELECT @MAX_LENGTH = 100
--SET @z = RAND() * (@max_length - @min_length + 1) + @min_length
SET @Z = 50
-- define allowable character explicitly - easy to read this way an easy to
-- omit easily confused chars like l (ell) and 1 (one) or 0 (zero) and O (oh)
SET @CharPool =
'abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ23456789.,-_!$@#%^&*'
SET @CharPool =
'ABCDEFGHIJKLMNPQRSTUVWXYZ'
SET @PoolLength = Len(@CharPool)
SET @i = 0
SET @RandomString = ''
WHILE (@i < @z) BEGIN
SELECT @RandomString = @RandomString +
SUBSTRING(@Charpool, CONVERT(int, RAND() * @PoolLength), 1)
SELECT @i = @i + 1
END
SELECT @STR = @RandomString
end
GO
create procedure GetRandomNumber (@number int OUTPUT)
as
begin
-- generate random numbers
-- marcelo miorelli
-- 01-oct-2014
DECLARE @maxval INT, @minval INT
select @maxval=10000,@minval=500
SELECT @Number = CAST(((@maxval + 1) - @minval) *
RAND(CHECKSUM(NEWID())) + @minval AS INT)
end
go
创建上述过程后,请参阅下面用于运行此测试的代码:
SELECT object_id AS ObjectID,
object_NAME (Object_id) as Table_NAME,
index_id AS IndexID,
avg_fragmentation_in_percent AS PercentFragment,
fragment_count AS TotalFrags,
avg_fragment_size_in_pages AS PagesPerFrag,
page_count AS NumPages
FROM sys.dm_db_index_physical_stats(DB_ID('dba'),
NULL, NULL, NULL , 'DETAILED')
WHERE OBJECT_ID = OBJECT_ID('tableSizeBenchmark')
and avg_fragmentation_in_percent > 0
所以结果如下: 在运行上述脚本但BEFORE ROLLBACK或COMMIT之后,事务仍处于打开状态:
请注意碎片已经增加。 在我们回滚此交易后,这种碎片会重新发生还是消失?
让我在这里发帖,我用来查看碎片级别的脚本:
SELECT object_id AS ObjectID,
object_NAME (Object_id) as Table_NAME,
index_id AS IndexID,
avg_fragmentation_in_percent AS PercentFragment,
fragment_count AS TotalFrags,
avg_fragment_size_in_pages AS PagesPerFrag,
page_count AS NumPages
FROM sys.dm_db_index_physical_stats(DB_ID('dba'),
NULL, NULL, NULL , 'DETAILED')
WHERE OBJECT_ID = OBJECT_ID('tableSizeBenchmark')
and avg_fragmentation_in_percent > 0
以及该实验的结果:
正如您所看到的,碎片级别在交易之前回到了原始状态。
希望这有帮助
马塞洛