我正在使用具有非聚集主键(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个秒。
答案 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列中放置