Sql server 顺序Guid和分段

Sql server 顺序Guid和分段,sql-server,guid,database-fragmentation,Sql Server,Guid,Database Fragmentation,我试图理解顺序guid如何比常规guid性能更好 是因为对于常规guid,索引使用guid的最后一个字节进行排序吗?因为它是随机的,所以会导致很多碎片和页面分割,因为它经常会将数据移动到另一个页面以插入新数据 顺序guid如果它是顺序的,它将导致更少的页面拆分和碎片 我的理解正确吗 如果有人能在这个问题上多加说明,我将不胜感激 多谢各位 编辑: 顺序guid=NEWSEQUENTIALID() 常规guid=NEWID()我遵从金伯利·L·特里普在这个话题上的智慧: 但是,GUID不是连续的-

我试图理解顺序guid如何比常规guid性能更好

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

顺序guid如果它是顺序的,它将导致更少的页面拆分和碎片

我的理解正确吗

如果有人能在这个问题上多加说明,我将不胜感激

多谢各位

编辑:

顺序guid=NEWSEQUENTIALID()


常规guid=NEWID()

我遵从金伯利·L·特里普在这个话题上的智慧:

但是,GUID不是连续的- 就像一个有价值的人 在客户端生成(使用.NET) 或由newid()函数生成 (在SQL Server中)可能是一个非常糟糕的问题 选择-主要是因为 它在数据库中创建的碎片 基表也是因为它的 尺寸。不必要的宽(4英尺) 比基于int的标识宽10倍 -这可以为您提供20亿(实际上是40亿)唯一行)。以及, 如果你需要超过20亿,你 可以始终使用bigint(8字节 int)并获取263-1行


阅读更多内容:

你的问题中几乎都说了

使用连续的GUID/主键,新行将添加到表的末尾,这使SQL server变得简单。相比之下,随机主键意味着新的记录可以插入到表中的任何地方-对于缓存中表的最后一页的可能性是相当可能的(如果这是所有读取的地方),但是在缓存中间表中的随机页的机会是相当低的,意味着需要额外的IO


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

可以使用可视化的方式来显示整个画面。 例如,您可以创建两个表:一个表的正常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后,索引的碎片更少,因为插入操作会导致新的页面分配更少。

您可能需要定义“顺序GUID”的含义,尤其是“常规GUID”。@Greg:我相信他指的是NEWSEQUENTIALID()生成的“顺序GUID”,而不是“常规GUID”由具有顺序Guid的NEWID()生成,因为它是顺序的,从技术上讲,所有新索引页在理论上都是顺序的,因此提高了性能。我理解正确吗?对于常规guid,记录会到处都是,因为它是随机的,因此对一个范围执行常规select语句可能会很慢?@pdiddy-因为“随机”guid不是顺序的,为什么要选择一个范围?关于顺序与随机的性质,您是正确的,然而真正的痛苦在于插入而不是选择。我明白了,插入是一个真正的痛苦,因为页面分割和碎片。但是一个带有连接的select也将是正确的,因为它必须进行大量的seek?我的意思是加入有PK的桌上也有正规的指南谢谢!我只是想确认我理解正确。