顺序Guid和碎片

时间:2010-08-10 14:33:19

标签: sql-server guid database-fragmentation

我试图了解顺序guid如何比常规guid更好。

是否因为使用常规guid,索引使用guid的最后一个字节进行排序?由于它是随机的,它会导致很多碎片和页面拆分,因为它经常将数据移动到另一个页面以插入新数据?

顺序guid正弦它是顺序的,它会导致很少的页面拆分和碎片?

我的理解是否正确?

如果有人能够更多地了解这个话题,我会非常感激。

谢谢

编辑:

顺序guid = NEWSEQUENTIALID(),

常规guid = NEWID()

3 个答案:

答案 0 :(得分:9)

你在问题​​中已经说了很多。

使用顺序GUID /主键,新行将在表的末尾添加在一起,这使得SQL服务器很容易。相比之下,随机主键意味着可以在表中的任何位置插入新记录 - 表的最后一页在缓存中的可能性很大(如果这是所有读取的位置),但是表中间的随机页面位于缓存中相当低,这意味着需要额外的IO。

最重要的是,当将行插入表格的中间时,可能没有足够的空间来插入额外的行。如果是这种情况,则SQL服务器需要执行额外的昂贵IO操作以便为记录创建空间 - 避免这种情况的唯一方法是在数据之间分散间隙以允许插入额外的记录(称为填充因子),这本身会导致性能问题,因为数据分布在更多页面上,因此访问整个表需要更多的IO。

答案 1 :(得分:3)

我尊重Kimberly L. Tripp关于这个话题的智慧:

  

但是,GUID不是顺序的 -   就像有价值观的人一样   在客户端生成(使用.NET)   或者由newid()函数生成   (在SQL Server中)可能非常糟糕   选择 - 主要是因为   它创造的碎片化   基表也因为它   尺寸。这是不必要的宽(它是4   时间宽于基于int的身份    - 它可以为您提供20亿(真正的,40亿)唯一行。和,   如果你需要超过20亿   总是可以使用bigint(8字节   int)并获得263-1行。

了解详情:http://www.sqlskills.com/BLOGS/KIMBERLY/post/GUIDs-as-PRIMARY-KEYs-andor-the-clustering-key.aspx#ixzz0wDK6cece

答案 2 :(得分:1)

可视化整个图片util named ostress可能会被使用。 例如。你可以创建两个表:一个表是普通 GUID作为PK,另一个表是顺序GUID:

-- normal one
CREATE TABLE dbo.YourTable(
   [id] [uniqueidentifier] NOT NULL,
   CONSTRAINT [PK_YourTable] PRIMARY KEY NONCLUSTERED (id)
);
-- sequential one
CREATE TABLE dbo.YourTableSeq(
   [id] [uniqueidentifier] NOT NULL CONSTRAINT [df_yourtable_id]  DEFAULT (newsequentialid()),
   CONSTRAINT [PK_YourTableSeq] PRIMARY KEY NONCLUSTERED (id)
);

然后使用给定的util运行一系列插入,并选择有关索引碎片的统计信息:

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTable VALUES (NEWID()); SELECT count(*) AS Cnt FROM dbo.YourTable; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTable';" -oE:\incoming\TMP\ -n1 -r10000

ostress -Slocalhost -E -dYourDB -Q"INSERT INTO dbo.YourTableSeq DEFAULT VALUES; SELECT count(*) AS Cnt FROM dbo.YourTableSeq; SELECT AVG_FRAGMENTATION_IN_PERCENT AS AvgPageFragmentation, PAGE_COUNT AS PageCounts FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, N'LIMITED') DPS INNER JOIN sysindexes SI ON DPS.OBJECT_ID = SI.ID AND DPS.INDEX_ID = SI.INDID WHERE SI.NAME = 'PK_YourTableSeq';" -oE:\incoming\TMP\ -n1 -r10000

然后在文件E:\ incoming \ TMP \ query.out中,您将找到您的统计信息。 我的结果是:

"Normal" GUID:
Records    AvgPageFragmentation     PageCounts           
---------------------------------------------- 
1000       87.5                     8                    
2000       93.75                    16                   
3000       96.15384615384616        26                   
4000       96.875                   32                   
5000       96.969696969696969       33                   
10000      98.571428571428584       70                   


Sequential GUID:
Records    AvgPageFragmentation     PageCounts           
---------------------------------------------- 
1000       83.333333333333343       6                    
2000       63.636363636363633       11                   
3000       41.17647058823529        17                   
4000       31.818181818181817       22                   
5000       25.0                     28                   
10000      12.727272727272727       55       

正如您所看到的那样,插入顺序生成的GUID时,索引的碎片要少得多,因为插入操作会导致新页面分配更少。