2

我知道,有些原因索引碎片是交易:更新和插入可能导致索引碎片,即使你回滚

非顺序插入 - 做一个非顺序插入,SQL Server会将〜50%时,从旧页面到新分配页面的数据。这会导致页面拆分,每页有大约50%来自旧页面的数据。

更新到具有更大价值的现有行的值,它不适合在同一页上

我听说即使你回滚事务,碎片仍然存在,但我找不到文档那。

是否有人有文档或者脚本来证明这一点?

+2

你尝试过什么?把一张表与索引放在一起。使用guid作为聚簇索引,使分段变得容易。添加约5k行,检查碎片。然后做你的插入和回滚,再次检查碎片。 – 2014-09-30 13:29:35

回答

0

今天我做了一些测试,结果并不完全符合我的预期。

环境:

的Microsoft SQL Server 2008(SP2) - 10.0.4000.0(X64)2010年9月16日19时43分16秒版权所有(C)1988-2008微软公司企业版(64位)上Windows NT 6.0(Build 6002:Service Pack 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 

这是分裂的水平之前进行任何测试:

enter image description here

你需要为了进行相同的测试,以创建这些程序2。 基本上我使用了随机字符串生成器和一个随机数生成器,只是因为我想插入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.,[email protected]#%^&*' 

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 

所以结果: 运行上面的脚本之后,但在回滚或提交,交易仍然是开放的:

enter image description here

请注意碎片有所增加。 在我们回滚这个事务之后,这个碎片是REMAIN还是DISAPPEAR?

让我也张贴在这里,我用它来看看碎片级别的脚本:

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 

这个实验的结果:

enter image description here

正如你所看到的,在交易之前,碎片化水平回到原来的状况。

希望这有助于

马塞洛

相关问题