建议请:使用实体框架时SQL Server身份与唯一标识符密钥

Cur*_*att 3 sql-server replication identity entity-framework uniqueidentifier

我正在设计一个相当复杂的系统.我们主要关注的一个问题是支持SQL Server对等复制.这个想法是支持几个地理上分离的节点.

第二个问题是在中间层使用现代ORM.我们的第一选择一直是实体框架,主要是因为开发人员喜欢使用它.(他们喜欢LiNQ的支持.)

所以这就是问题所在:

考虑到点对点复制,我决定使用uniqueidentifier,默认值为newsequentialid(),用于每个表的主键.这似乎在避免关键冲突和减少索引碎片之间提供了良好的平衡.

但是,事实证明当前版本的Entity Framework有一个非常奇怪的限制:如果实体的键列是唯一标识符(GUID),则它不能配置为使用数据库提供的默认值(newsequentialid()).应用程序层必须生成GUID并填充键值.

所以这是辩论:

  1. 放弃实体框架并使用另一个ORM:
    • 使用NHibernate并放弃LiNQ支持
    • 使用linq2sql并放弃将来的支持(更不用说绑定到DB上的SQL Server)
  2. 放弃GUID并采用另一种PK策略
  3. 设计一种在应用层生成顺序GUID(COMB?)的方法

我倾向于选择1使用linq2sql(我的开发人员非常喜欢linq2 [stuff])和3.这主要是因为我对支持我们所追求的复制方案的备用关键策略有点无知,同时也保持了理智.开发人员的观点.

任何见解或意见将不胜感激.

mar*_*c_s 8

我是克雷格的第二个建议 - 选项4.

您始终可以使用由中间层填充的GUID列作为PRIMARY KEY(这是一个LOGICAL构造).

为了避免大量索引(因此:表)碎片,使用一些其他键(理想情况下为INT IDENTITY列)作为CLUSTERING KEY - 这是一个物理数据库构造,可以与主键分开.

默认情况下,主键是群集键 - 但不一定是这样.实际上,我通过在"继承"的数据库上做了这样的改进来提高性能并大幅降低碎片 - 添加一个INT IDENTITY列并将聚类键放在那个小的,不断增加的,永不改变的INT上 - 就像一个魅力!


Cra*_*ntz 5

咦?我认为你的三个选择都是错误的选择.考虑选项4:

4)将实体框架与非顺序的,客户端生成的GUID一起使用.

当然,EF无法查看由框架本身插入的新行的DB服务器生成的GUID,但您不需要在数据库服务器上生成GUID.您可以在创建实体实例时在客户端上生成它们.GUID的重点在于您生成它的位置无关紧要.至于复制数据库生成的GUID,EF会很好地看到它们.

您的客户端GUID将不是顺序的(使用Guid.NewGuid()),但它们将在全球范围内保证唯一.

我们在运输,生产软件中进行复制.它确实有效.

  • 如果您还在GUID列上设置CLUSTERING KEY,则只会产生大量的表碎片.但是你没必要!您可以将PRIMARY KEY保留在GUID列上,并使用不断增加的IDENTITY列作为您的CLUSTERING KEY - >没有碎片可言! (4认同)
  • 真正随机的GUID会导致表碎片和页面拆分,从而降低性能.我发现了一些关于在中间层生成合适的顺序GUID的文章.这似乎是目前最好的选择. (2认同)
  • @Craig它还为URI提供了一个轻松"可篡改"的密钥:) (2认同)
  • @annakata和Adam,我认为URI中的"秘密"不是.恕我直言,GUID的目的是分散唯一ID生成.应使用身份验证和授权来处理直接对象引用安全性,而不是模糊的URI. (2认同)