使用GUID非集群PK将记录插入表中时插入性能较差

时间:2019-03-22 21:21:24

标签: sql-server

我正在使用具有非聚集主键(GUID)和附加聚集索引(int)的表对SQL Server 2017的插入性能进行基准测试。虽然我预计性能会比自动增量整数PK有所下降,但我得到的指标似乎并不合理-使用GUID PK插入表的时间实际上要长70倍。

表格:

[Table1]
(
    [Id] [INT] IDENTITY(1,1) NOT NULL, <-- clustered PK
    [Prop_s1] [NVARCHAR](MAX) NULL,
    [Prop_s2] [NVARCHAR](MAX) NULL,
    ...
    [Prop_b3] [BIT] NULL,
    [Prop_n3] [DECIMAL](18, 2) NULL
)

[Table2]
(
    [Id] [UNIQUEIDENTIFIER] NOT NULL, <-- non-clustered PK
    [Prop_s1] [NVARCHAR](MAX) NULL,
    [Prop_s2] [NVARCHAR](MAX) NULL,
    ...
    [Prop_b3] [BIT] NULL,
    [Prop_n3] [DECIMAL](18, 2) NULL,
    [ClusterId] [INT] IDENTITY(1,1) NOT NULL, <-- clustered
)

查询看起来像

Insert into Table (....)
    select ....
    union all
    select ....

表2的ID是在客户端生成的。

两个表在结构上都是相同的。

我可以在大约550-600ms的时间内自动插入int PK来插入10k条记录。 使用guid键,每1万行大约需要35个

2 个答案:

答案 0 :(得分:3)

将随机GUID插入非集群PK具有与将随机GUID插入集群PK相同的问题,只是程度较小。每行放置在一个“随机”页面上,页面填满并且必须拆分。

使用非集群PK,您无需维护不必要的索引。

最好在Guid和NEWSEQUENTIALID()或客户端顺序GUID生成中包含聚簇索引。

客户端顺序GUID生成需要重新排序某些字节,以与SQL Server排序GUID的方式保持一致。在Windows上的C#中,它看起来像这样:

  public class SQLGuidUtil
  {
      [DllImport("rpcrt4.dll", SetLastError = true)]
      static extern int UuidCreateSequential(out Guid guid);

      public static Guid NewSequentialId()
      {
        Guid guid;
        UuidCreateSequential(out guid);
        var s = guid.ToByteArray();
        var t = new byte[16];
        t[3] = s[0];
        t[2] = s[1];
        t[1] = s[2];
        t[0] = s[3];
        t[5] = s[4];
        t[4] = s[5];
        t[7] = s[6];
        t[6] = s[7];
        t[8] = s[8];
        t[9] = s[9];
        t[10] = s[10];
        t[11] = s[11];
        t[12] = s[12];
        t[13] = s[13];
        t[14] = s[14];
        t[15] = s[15];
        return new Guid(t);
      }
  }

答案 1 :(得分:0)

尝试使用NEWSEQUENTIALID()而不是newid()来生成唯一标识符。通常,如果您在该表上发生大量插入,我会在IDENTITY列中放置