SQL主键

时间:2011-04-07 15:47:58

标签: asp.net sql-server tsql primary-key-design

所以,一位同事和我正在争论哪种方式更适合生成GUID的主键。

我们正在使用带有实体4的.NET 4.0并使用存储过程来进行选择/插入/更新。

他希望在代码中创建GUID主键,并使用Guid类或/并使用一些创建的Sequential GUID类将其作为插入的一部分传回。

我希望使用newid()或newsequentialid()在插入时由SQL Server创建GUID。

我反对他的方式的论点是,如果你必须进行多次插入,你必须进行往返以获取每个插入的guid,以便为外键约束维护该关系。另外,使用这种方式你必须为每个插件进行几次往返。

他关于使用SQL做的论点是,在插入发生之前他无法访问密钥,并且必须等待插件发生以使主键guid重新用于代码的其他部分。这样,您就可以建立一个与存储过程的连接,并处理所有插入。

那么,对于单个插入哪种方法更好?哪种方法更适合事务中的多个插入?

2 个答案:

答案 0 :(得分:12)

GUID似乎是您主键的自然选择 - 如果您真的必须,您可能会争辩将其用于表的PRIMARY KEY。我强烈建议不要使用GUID列作为群集密钥,默认情况下SQL Server会执行此操作,除非您明确告知不要这样做。

你真的需要分开两个问题:

1)主键是一个逻辑结构 - 唯一且可靠地标识表中每一行的候选键之一。这可以是任何东西,真的 - 一个INT,一个GUID,一个字符串 - 选择对你的场景最有意义的东西。

2)群集密钥(定义"聚集索引"在表上的一列或多列) - 这是物理存储 - 相关的东西,在这里,一个小的,稳定的,不断增加的数据类型是你最好的选择 - INT或BIGINT作为你的默认选项。

默认情况下,SQL Server表上的主键也用作群集键 - 但这不是必须的! I' - 对GUID主(逻辑)键,在一个单独的INT IDENTITY聚类(排序)键(分手时,前面的基于GUID的主/聚集键分成两个单独的密钥已经亲眼见过巨大的性能提升1,1)专栏。

作为Kimberly Tripp - 索引女王 - 以及其他人已多次说过 - GUID作为聚类键并不是最佳的,因为由于其随机性,它将导致大量页面和索引碎片化和一般性能不佳。

是的,我知道 - 在SQL Server 2005及更高版本中有newsequentialid() - 但即使这样也不是真正完全顺序的,因此也会遇到与GUID相同的问题 - 只需少一点显着如此。如果坚持在GUID上,那么至少会在服务器上使用newsequentialid()方法!

然后还有另外一个需要考虑的问题:表格上的聚类键也会添加到表格中每个非聚集索引的每个条目上 - 因此你真的想确保它和#39; s尽可能小。通常,对于绝大多数表来说,具有2亿行的INT应该足够 - 并且与作为群集密钥的GUID相比,您可以在磁盘和服务器内存中节省数百兆的存储空间。

快速计算 - 使用INT与GUID作为主要和群集密钥:

  • 基本表,1' 000' 000行(3.8 MB对15.26 MB)
  • 6个非聚簇索引(22.89 MB vs. 91.55 MB)

TOTAL:25 MB vs. 106 MB - 这只是在一张桌子上!

更多值得思考的东西 - 金佰利特里普的优秀作品 - 阅读,再读一遍,消化它!它确实是SQL Server索引福音书。

马克

答案 1 :(得分:1)

当我有这样的问题时,我对自己说“SQL Server擅长集合,所以让它让它做得好”,有时“1只是N的特定情况”。

  

哪种方法更适合单身   插入

对于同步sql调用的任何一种方法,单个插入时间都是相同的。然而,“他的”方法会给你更多的问题,因为他的顺序guid方法不会像sql服务器一样 good (你可能会丢失)全球唯一性)。当您不可避免地需要进行多次插入时,它还会拆分您的代码库。

  

哪种方法更适合多种方法   在事务中插入?

如果您正在争论基于集合的插入(插入/选择)v.s.单行插入(插入),基于集合将在多个插入上获胜,因为回到客户端的行程将是昂贵的部分。

如果这是我,我会创建一个SP,它接受要插入的对象的序列化集合,使用output clause进行插入/选择,检查“示例B.使用带有标识和计算列的OUTPUT”在this page上,让sql server创建GUID(如果你被卡在上面)并返回客户端或运行SP中的下一个语句,根据你的插件生成的输出表插入子行。