为什么使用NEWID()比NEWSEQUENTIALID()使用更多的空间?

时间:2014-01-07 14:23:19

标签: sql-server tsql guid newid newsequentialid

我正在做一些研究,我遇到了一个我无法解释的异常(而且我无法在谷歌上找到任何东西)。请考虑以下SQL:

CREATE TABLE MyGuid (
    ID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWID()
)
GO
CREATE TABLE MyGuidSeq (
    ID UNIQUEIDENTIFIER PRIMARY KEY DEFAULT NEWSEQUENTIALID()
)
GO

DECLARE @i INT, @noRecords INT
SET @noRecords = 1000000

-- MyGuid
SET @i = 1
WHILE (@i <= @noRecords)
    BEGIN
        INSERT INTO MyGuid DEFAULT VALUES
        SET @i = @i + 1
    END

-- MyGuidSeq
SET @i = 1
WHILE (@i <= @noRecords)
    BEGIN
        INSERT INTO MyGuidSeq DEFAULT VALUES
        SET @i = @i + 1
    END

exec sp_spaceused 'MyGuid', true
exec sp_spaceused 'MyGuidSeq', true

结果:

Table name  No. Rows   Reserved Space  Actual space  Index Size  Unused Space
MyGuid      1,000,000  34,760 KB       34,552 KB     160 KB      48 KB
MyGuidSeq   1,000,000  24,968 KB       24,768 KB     176 KB      24 KB

问题

有人解释为什么在使用NEWSEQUENTIALID()而不是NEWID()时保留/实际空间要小得多吗?

回复

我进行了以下测试以检查Luaan给出的答案:

CREATE TABLE MyGuid (
    ID UNIQUEIDENTIFIER DEFAULT NEWID()
)
GO
CREATE TABLE MyGuidSeq (
    ID UNIQUEIDENTIFIER DEFAULT NEWSEQUENTIALID()
)
GO

DECLARE @i INT, @noRecords INT
SET @noRecords = 1000000
-- MyGuid
SET @i = 1
WHILE (@i <= @noRecords)
    BEGIN
        INSERT INTO MyGuid DEFAULT VALUES
        SET @i = @i + 1
    END

-- MyGuidSeq
SET @i = 1
WHILE (@i <= @noRecords)
    BEGIN
        INSERT INTO MyGuidSeq DEFAULT VALUES
        SET @i = @i + 1
    END

exec sp_spaceused 'MyGuid', true
exec sp_spaceused 'MyGuidSeq', true

不同之处在于我删除了主键(意味着表现在是一个堆表)。现在,这两个表的大小完全相同。这证明该表是通过其聚簇索引进行物理组织的。

name       rows    reserved  data      index_size  unused
MyGuid     1000000 25992 KB  25976 KB  8 KB        8 KB
MyGuidSeq  1000000 25992 KB  25976 KB  8 KB        8 KB

1 个答案:

答案 0 :(得分:4)

这与分区有关。基本上,newId()将以随机顺序创建GUID,这意味着您将一直插入到表的中间。另一方面,顺序ID将始终附加到表的末尾,这更简单。

如果您想了解更多信息,请查看有关分页的一些材料。一个好的开始可能是MS SQL分页上的官方MSDN页面 - http://technet.microsoft.com/en-us/library/ms190969(v=sql.105).aspx

您还必须了解行在存储数据库数据的物理文件中通过ID固有地进行组织。 ID之间没有空格的文件(例如使用标识列和不删除时)可以占用更少的空间来存储相同数量的数据。

我希望数据库的完全缩减将显着减少MyGuid表中碎片丢失的空间量,同时它对MyGuidSeq大小的影响非常小。

如果可以使用顺序GUID,那么这样做 - 它们可以大大提高INSERT效率,而且通过扩展,索引也可以更少碎片化,整体上更小。

你没有显示“花费时间”调试输出,但我希望它们也有很大不同(尽管这可以被数据库可用的内存大大抵消 - 它不需要改变数据文件立即;如果您想了解更多相关信息,请查看有关事务日志的内容。