我试图了解顺序guid如何比常规guid更好。
是否因为使用常规guid,索引使用guid的最后一个字节进行排序?由于它是随机的,它会导致很多碎片和页面拆分,因为它经常将数据移动到另一个页面以插入新数据?
顺序guid正弦它是顺序的,它会导致很少的页面拆分和碎片?
我的理解是否正确?
如果有人能够更多地了解这个话题,我会非常感激。
谢谢
编辑:
顺序guid = NEWSEQUENTIALID(),
常规guid = NEWID()
答案 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行。
答案 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时,索引的碎片要少得多,因为插入操作会导致新页面分配更少。