当前位置: 首页 > 面试题库 >

在聚簇索引上使用顺序GUID键的INSERT不会明显更快

祁绪
2023-03-14
问题内容

在SQL Server 2008中,我尝试重现来自顺序索引和非顺序GUID密钥的聚集索引的实验结果,此处的
http://sqlblog.com/blogs/denis_gobo/archive/2009/02/05/11743。
aspx,

但我并没有体验到我期望的(和作者所体验到的)插入速度的显着提高。顺序GUID明显提高了页面利用率,但是由于某些原因,插入10,000行仅快100毫秒左右(10,300毫秒中)。

我使用以下代码:

CREATE TABLE TestGuid1 (Id UNIQUEIDENTIFIER not null DEFAULT newid(),
SomeDate DATETIME, batchNumber BIGINT)

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER not null DEFAULT newsequentialid(),
SomeDate DATETIME, batchNumber BIGINT)

CREATE CLUSTERED INDEX ix_id1 ON TestGuid1(id)
CREATE CLUSTERED INDEX ix_id2 ON TestGuid2(id)

go

SET NOCOUNT ON
INSERT TestGuid1 (SomeDate,batchNumber) VALUES (GETDATE(),3)
go 10000

SET NOCOUNT ON
INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),3)
go 10000

DBCC showcontig ('TestGuid1') WITH tableresults
DBCC showcontig ('TestGuid2')  WITH tableresults

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate))
FROM TestGuid1
GROUP BY batchNumber

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate))
FROM TestGuid2
GROUP BY batchNumber

谁能解释为什么我在TestGuid2上没有更快的插入速度?

后续按照
下面线程中的要求,我扩大了测试范围:测试结果倾向于随时间变化很大,因此现在将实验重复N次,并报告总和平均使用时间。我还添加了第三项测试,即针对顺序整数列上的主键。这应该是这三种方法中最快,最紧凑的,因为整数类型较小并且IDENTITY(1,1)快(或至少应该快)。至少根据我的直觉。现在,
平均 执行时间有益于顺序GUID,但是令人惊讶的是,在第三个实验中(使用顺序整数键)插入的 速度 比顺序GUID
。我对此没有任何解释。这是新实验的代码:

SET NOCOUNT ON

CREATE TABLE TestGuid1 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

CREATE TABLE TestInt (Id Int NOT NULL identity(1,1) PRIMARY KEY,
SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

DECLARE @BatchCounter INT = 1
DECLARE @Numrows INT = 100000


WHILE (@BatchCounter <= 20)
BEGIN 
BEGIN TRAN

DECLARE @LocalCounter INT = 0

    WHILE (@LocalCounter <= @NumRows)
    BEGIN
    INSERT TestGuid1 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
    SET @LocalCounter +=1
    END

SET @LocalCounter = 0

    WHILE (@LocalCounter <= @NumRows)
    BEGIN
    INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
    SET @LocalCounter +=1
    END

SET @LocalCounter = 0

    WHILE (@LocalCounter <= @NumRows)
    BEGIN
    INSERT TestInt (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
    SET @LocalCounter +=1
    END

SET @BatchCounter +=1
COMMIT 
END

DBCC showcontig ('TestGuid1') WITH tableresults
DBCC showcontig ('TestGuid2')  WITH tableresults
DBCC showcontig ('TestInt')  WITH tableresults

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWID()]
FROM TestGuid1
GROUP BY batchNumber

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
FROM TestGuid2
GROUP BY batchNumber

SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [IDENTITY()]
FROM TestInt
GROUP BY batchNumber

DROP TABLE TestGuid1
DROP TABLE TestGuid2
DROP TABLE TestInt

平均 执行时间:

NEWID()            3064
NEWSEQUENTIALID()  1977
IDENTITY()         2223

页面用法如下:

Table          Pages  AveragePageDensity
----------------------------------------
TestGuid1      50871  68,4
TestGuid2      35089  99,2
TestInt        32259  98,7

我看不到,为什么这些网页统计信息(最适合TestInt)并不意味着实验3最快。


问题答案:

您可以尝试修改后的脚本并发布结果吗?

    SET NOCOUNT ON

    CREATE TABLE TestGuid1 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID() PRIMARY KEY,
    SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

    CREATE TABLE TestGuid2 (Id UNIQUEIDENTIFIER NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY,
    SomeDate DATETIME, batchNumber BIGINT, FILLER CHAR(100))

    DECLARE @BatchCounter INT = 1

    WHILE (@BatchCounter <= 20)
    BEGIN 
    BEGIN TRAN

    DECLARE @LocalCounter INT = 0

        WHILE (@LocalCounter <= 100000)
        BEGIN
        INSERT TestGuid1 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
        SET @LocalCounter +=1
        END

    SET @LocalCounter = 0

        WHILE (@LocalCounter <= 100000)
        BEGIN
        INSERT TestGuid2 (SomeDate,batchNumber) VALUES (GETDATE(),@BatchCounter)
        SET @LocalCounter +=1
        END

    SET @BatchCounter +=1
    COMMIT 
    END

    DBCC showcontig ('TestGuid1') WITH tableresults
    DBCC showcontig ('TestGuid2')  WITH tableresults

    SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWID()]
    FROM TestGuid1
    GROUP BY batchNumber

    SELECT batchNumber,DATEDIFF(ms,MIN(SomeDate),MAX(SomeDate)) AS [NEWSEQUENTIALID()]
    FROM TestGuid2
    GROUP BY batchNumber

DROP TABLE TestGuid1
DROP TABLE TestGuid2

我发现各个运行之间的结果差异很大(在我的笔记本电脑上而不是服务器上!),但是连续运行的明显趋势是更快。

NEWID() 均值5168.9

batchNumber          NEWID()
-------------------- -----------
1                    4270
2                    2480
3                    2706
4                    3333
5                    7480
6                    5346
7                    4306
8                    7713
9                    7313
10                   4760
11                   4680
12                   4113
13                   3433
14                   2686
15                   4963
16                   8040
17                   5313
18                   8160
19                   9533
20                   2750

NEWSEQUENTIALID() 均值3000.85

batchNumber          NEWSEQUENTIALID()
-------------------- -----------------
1                    2016
2                    1820
3                    1886
4                    1870
5                    4873
6                    3473
7                    3730
8                    3690
9                    1983
10                   2020
11                   1906
12                   5596
13                   2100
14                   1950
15                   2096
16                   1876
17                   5196
18                   2110
19                   2113
20                   7713


 类似资料:
  • 主要内容:一、索引的种类及常用术语,二、聚簇索引,三、InnoDB索引的数据结构,四、源码,五、总结一、索引的种类及常用术语 索引种类有很多种,象前面提到的聚集索引和非聚集索引(聚集和聚簇等同),还有多个条目生成的联合索引,非聚集索引又可以叫做二级索引,辅助索引(其它还有什么普通索引,唯一索引,全文索引都可以通过看具体的上下文场景来明白怎么回事),还有一些数据库默认在主键上建立主键索引,一般来说,一个数据库只有一个聚集索引,一个主键索引。 本篇主要分析取簇索引,一般来说,索引的深度不会超过4层,

  • 本文向大家介绍详解MySQL 聚簇索引与非聚簇索引,包括了详解MySQL 聚簇索引与非聚簇索引的使用技巧和注意事项,需要的朋友参考一下 1、聚集索引 表数据按照索引的顺序来存储的,也就是说索引项的顺序与表中记录的物理顺序一致。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。 在一张表上最多只能创建一个聚集索引,因为真实数据的物理顺序只能有一种。 从物理文件也可以看出 InnoD

  • 问题内容: 据我所知,堆表是没有聚簇索引并且没有物理顺序的表。我有一个具有12万行的堆表“扫描”,并且正在使用以下选择: 如果为“ id”列创建非聚集索引,则将获得 223次物理读取 。如果删除非聚集索引并更改表以使“ id”成为主键(以及聚集索引),则将获得 515次物理读取 。 如果聚集索引表如下图所示: 为什么聚簇索引扫描的工作方式类似于表扫描?(或者在检索所有行的情况下更糟)。为什么不使用

  • 问题内容: 当我查看特定查询的执行计划时,我发现我的成本的77%在聚簇索引查找中。 我使用聚集索引的事实是否意味着我不会因为输出的列而看到性能问题? 对我来说,创建一个非聚集版本并包含所有正在输出的列会更好吗? 更新:聚集索引使用组合键。不知道这是否有所作为。 问题答案: 使用非聚集索引上的包含列的原因是为了避免对聚集数据进行“书签查找”。问题是,如果SQL Server _理论上可以_使用特定的

  • 问题内容: 我在我的WEB Api项目中使用了Entity Framework。我使用代码优先迁移。 事情是:进行初始迁移并尝试更新数据库后,出现此错误 不正确使用空间/全文/哈希索引和显式索引顺序 这是由更新数据库中的此SQL命令引起的: SQL命令是从迁移中的以下代码生成的: 似乎在创建索引时出现DESC和HASH会导致此错误。关于如何更改生成的sql索引创建的任何想法,使其与简单的索引一起使

  • 问题内容: 为了在SQL Azure上使用Fluent NHibernate映射,我需要在每个表上都有一个聚集索引。Fluent NHibernate为多对多联接创建的默认堆表显然不这样做,因为它们没有主键。 我希望能够告诉关系的一方为其连接表创建聚簇索引,但是我不确定如何。这是我的映射的样子: 如果您需要更多信息,请告诉我! 问题答案: 我不知道Fluent是否直接支持它(如果不支持,只需包含x