我们使用Guids作为数据库中实体的主键。传统上,我们遵循一种模式,让数据库在INSERT期间设置实体的ID,我想主要是因为这通常是你使用自动增量字段或其他任何东西处理事物的方式。
我发现在对象构建期间在代码中进行键分配更加方便,主要有两个原因:
- 你知道,一旦对象的构造函数运行,它的所有字段都已初始化。你永远不会有“半生不熟”的物体。
- 如果你需要做一批操作,其中一些操作依赖于知道一个对象的密钥,你可以一次完成所有这些操作而不需要往返于数据库。
有没有令人信服的理由 不 以这种方式做事?也就是说,当使用Guids作为密钥时,是否有充分的理由将密钥分配留给数据库?
编辑:
很多人都对Guid是否应该用于PK(我知道)有强烈的意见,但这不是我的问题。
除了集群问题(如果正确设置索引似乎没有问题),我还没有看到避免在应用程序层中创建密钥的令人信服的理由。
我认为你在客户端创建它们做得很好。正如您所提到的,如果您让数据库执行此操作,您必须找到一些方法(不能想到任何真正的方法)来获取该密钥。如果您使用的是标识,则可以使用调用来获取为表创建的最新标识,但我不确定是否存在guid。
通过在C#中执行此操作,您可能会冒着重新分配GUID并将其保存回数据库的风险。通过让数据库对其负责,您可以保证这个PK不会改变,也就是说,如果您设置了适当的约束。话虽如此,您可以在C#代码中设置类似的约束,防止在分配后更改唯一ID,但是您必须在所有应用程序中执行相同操作...在我看来,在C#中使用它听起来比数据库更加维护,因为数据库已经内置了防止更改主键的方法。
有趣的问题。
传统上我也使用了DB分配的guid,但最近我正在使用Windows Mobile应用程序而SQL CE数据库不允许使用newguid所以我必须在代码中执行它。
我使用SQL复制将数据从移动设备获取到服务器。在过去的6个月里,我有40个SQL CE客户端将超过100000条记录同步回SQL 2005服务器而没有一个错过或重复的guid。
所需的额外编码可以忽略不计,插入前知道guid的好处实际上减少了一些复杂性。
我没有进行任何性能检查,所以性能除了我看不出任何理由不按照你的建议实现guid处理。
GUID对于表现非常糟糕
我会把它留在数据库中,特别是现在SQL Server有 NEWSEQUENTIALID() 因为值是随机的,所以不会导致插入页面拆分,每个创建的NEWSEQUENTIALID都将大于前一个...只有caviat是它只能用作默认值
如果您不得不在GUI之外进行插入(考虑从其他供应商导入或从您购买的公司获取数据并且必须与您的数据合并),则不会自动分配GUID。这不是一个不可逾越的问题,但它仍然需要考虑。
我让一个空的Guid指示这个对象虽然已构建,但尚未插入(或从中检索)数据库。
正如SQLMenace所指出的那样,标准GUID会对索引和分页产生负面影响。在C#中,您可以使用一点P / Invoke乐趣生成顺序GUID,如NEWSEQUENTIALID()。
[DllImport("rpcrt4.dll", SetLastError = true)]
static extern int UuidCreateSequential(out Guid guid);
这样您至少可以继续使用GUID,但可以更灵活地生成它们的方式和位置。
好的,是时候进入了。我会说生成的GUID客户端用于保存到数据库是最好的方法 - 只要你碰巧使用GUID作为你的PK,我只推荐在一个场景中:断开连接环境。
当您使用断开连接的模型进行数据传播时(即PDA /手机应用程序,用于有限连接方案的笔记本电脑应用程序等),作为PK生成客户端的GUID是最好的方法。
对于其他所有情况,您可能最好使用自动增量标识PK。
为什么?好吧,有几个原因。首先,通过使用行跨越聚簇PK索引,您确实可以获得巨大的性能提升。 GUID PK和聚集索引不能很好地协同工作 - 即使使用NEWSEQUENTIALID,顺便说一下,我认为完全错过了GUID的重点。其次,除非您的情况迫使您不要(即您必须使用断开连接的模型),否则您确实希望保持所有事务处理并同时插入相同数量的相关数据。
除了群集问题(如果正确设置索引,这似乎不是问题),
作为索引的GUID总是非常混乱 - 没有“正确”的设置来避免这种情况(除非你在SQL Server引擎中使用NEWSEQUENTIALGUID函数)。
IMHO的最大缺点是大小 - GUID是16字节,INT是4.PK不仅存储在主键的树中,而且还存储在每个非聚集索引条目中。
有几千个条目,这可能没什么大不同 - 但如果你有一个包含数百万或数十亿条目和几个非聚集索引的表,使用16字节GUID而不是像PK那样的4字节INT所需空间的巨大差异 - 磁盘和RAM。
渣子