SQL Server Int或BigInt数据库表ID

66

我正在编写一个新程序,它将需要一个数据库(SQL Server 2008)。目前系统中的所有内容都是64位的,这就带来了一个问题。对于各种表中的所有Id列,我应该将它们全部设置为INT还是BIGINT?我怀疑系统将永远不会超过INT范围,但在某些更大的财务表中可能存在这种可能性。尽管如此,INT似乎是标准...

7个回答

139

好的,让我们快速回顾一下数学:

  • INT 是32位的,可以给你大约40亿个值 - 如果你只计算大于零的值,那就是20亿。你有这么多员工吗?客户?库存产品?公司的生命周期中的订单数量?真的吗?

  • BIGINT 超出了这个范围。你真的需要它吗?如果你是天文学家或者研究粒子物理学,也许需要。但普通的商业用户,我强烈怀疑。

想象一下你有一个有1000万行记录的表(你公司的订单)。比如说你有一个 Orders 表,其中 OrderID 使用 BIGINT 类型,并且被其他5个表所引用,在 Orders 表上还有5个非聚集索引 - 我觉得这并不过分,对吧?

1000万行,乘以 5 个表再加上 5 个非聚集索引,这使得你使用的是每条记录8字节而不是4字节 - 400百万字节 = 400 MB。完全浪费......你会需要更多的数据和索引页面,你的SQL Server将不得不从磁盘读取更多页面并缓存更多页面......这对你的性能没有好处 - 简单明了。

此外,大多数程序员不会想到的是:是的,磁盘空间很便宜。但是那些浪费的空间也会影响到SQL Server的RAM内存和数据库缓存 - 而那部分空间可不便宜!

因此,为了让长篇大论变得简短,使用最小化的 INT 类型来满足你真正需要的需求;如果你需要处理10-20个不同的值 - 使用 TINYINT。如果你需要一个订单表,我相信 INT 应该完全够用了 - BIGINT 只会浪费空间。

另外:如果你的任何一个表真的接近于达到20或40亿行,那么你仍然有足够的时间将你的表升级为 BIGINT ID,如果真的需要的话.......


6
我实际上必须执行这样的更新,你说得对,我们有超过6个月的警告时间,而且这并不难做。具有讽刺意味的是,在下一个版本中,整个关键字将要消失,因为它真的没有必要。通常我不喜欢自然键,但当你的表中有数十亿行时,就该考虑使用它们了;100GB的更多可用磁盘空间和插入5万行时需要更新的一个索引少了,这是非常好的激励。 - Aaronaught
35
考虑 ATT:假设有1亿客户每日发送1条短信,仅一个月就需要处理30亿条记录,这些记录都需要一个ID字段。我在一家手机公司工作(不是ATT),我觉得你对bigint的反对是没有必要的,也缺乏想象力。对于像手机服务这样日常琐事来说,int类型已经无法满足需求。尽管如此,我依然欣赏你所说的其他内容。 - user38858
4
使用 BIGINT 身份标识符,这对 AT&T 只有大约 300 万个月的有效期。 - marc_s
25
我举了一个相关且真实的例子,说明int不足以满足需求。不确定为什么你要对此嘲讽。如果你对这个例子有疑虑,或者认为对于手机元数据来说int已经足够,请告诉我。我一直在努力做得更好。 - user38858
这是一个老话题,但没关系。在选择int或bigint之间时,您需要考虑到,如果您想不断移动行而不重复使用已删除的键(例如将其转移到存档中,因此从某个表中删除,但您希望在整个系统中保留键而不重复它们)。 - szab.kel
错误,你想的是无符号整数,因为 INT 只能提供大约 21 亿个值。INT UNSIGNED 可以提供大约 42 亿个值。(除非负 ID 是可以接受的...这是非常不寻常的) - hanshenrik

18

以下是关于性能的真实解答文章...如果可能的话,我更愿意用硬数据回答问题...如果您点击以下链接至少达到一百万条记录,您会发现磁盘使用差异微不足道...

http://www.sqlservercentral.com/articles/Performance+Tuning/2753/

个人认为使用适当的 ID 大小很重要,但同时也要考虑到您可能有表格随时间而产生大量活动。这并不是存储大量数据,而是由于自动增加(删除和插入在此期间发生)而导致键值增长的性质。

考虑到一个社区网站上的文件库,或多租户应用程序上的用户评论 ID。

我知道大多数开发者正在构建永远不会触及数百万条记录的系统,但重要的是要注意,存在需要 bigint 的原因,并且我仍然不相信当您设计一个模式时,您不知道该模式可能增长到何种程度时,您不应该试图预测未来并考虑使用 bigint 如果您认为存在超过 int 的最大值的潜力作为 ID 值增长的情况。


2
请添加链接文章中的相关信息,因为它似乎需要注册才能查看。 - xpereta
不再需要注册啦 \o/ - Pedro Lorentz

17

应该使用对于相关表而言有意义的最小数据类型。这包括在行数较少时甚至可以使用smallinttinyint

这样可以节省数据和索引空间,并获得更好的索引性能。当需要的只是smallint时,使用bigint类似于使用varchar(4000)而实际上只需要varchar(50)

即使机器的本机字长为64位,这只意味着64位CPU操作不会比32位操作任何慢。大多数情况下,它们也不会更快,它们将是相同的。但是,大多数数据库不太可能受到CPU限制,它们将受到I/O限制和较小程度上的内存限制,因此当需要在2亿行上执行索引扫描时,50%-90%更小的数据大小是一个非常好的事情。


5
@Aaronaught 很好的帖子 +1,但有个问题;我之前认为 varchar(50)、varchar(4000) 和 varchar(max) 对于小于50个字符的给定字符串占用的空间都相同,区别只在于SQL对字段大小的限制。(http://msdn.microsoft.com/en-us/library/aa258242(SQL.80).aspx) - Hogan
8
@Hogan: 很好的观点。对于准确描述领域需求来说,合理的最大尺寸更好,但更好的类比可能是 char(10)char(50) - Aaronaught

6

32位数字在x86架构或64位数字在x64架构中的对齐称为数据结构对齐

这对于数据库中的数据没有意义,因为磁盘空间、数据缓存和表/索引结构等因素会影响性能(如其他答案所述)。

请记住,CPU并不是直接访问数据。运行在CPU上并操作您的数据的是DB引擎代码(可能会进行对齐,但谁在乎呢?)。如果您的数据通过CPU,则它肯定不会在相同的磁盘结构中。


5
第一个答案是对于那些没有处理TB级大小的数据库或常量和高频插入表的人而言的天真的答案。在任何体量较大的数据库中,您都将在某个阶段遇到INT问题。如果必须使用,则应使用BIGINT,因为这将在以后避免很多麻烦。我曾经看到一些公司仅仅存储了一年的数据就遇到INT问题,而且无法进行重新排序,这导致了巨大的停机时间。此外,在长期运行的系统(10年以上)中,即使是在清除旧数据的中等大小的数据库中也会遇到它,而该系统不希望仍然被使用。在大多数情况下最好使用GUID,但如果需要的话可以使用BIGINT。

我也支持GUIDS,因为客户端生成GUID COMB可以减少往返次数。 - Reasurria

5
其他人已经给出了关于32位ID的令人信服的答案。
对于某些应用程序来说,64位ID确实更有意义。
如果您希望确保ID在数据库集群中是唯一的,则63位ID非常方便。使用32位,将ID的生成分布到群集中的服务器或数据中心非常困难。而使用64位,您可以轻松地在服务器之间生成ID而无需锁定,并且仍然可以保证唯一性。
例如,请查看Twitter SnowflakeInstagram Engineering's blog post on "Sharding & IDs at Instagram"。两者都提供了为什么63位或64位比32位计数器更适合其ID的充分理由。

4

您应该根据每个表格的需求单独判断使用哪种数据类型。如果一个整数可以满足特定表格的需要,那么就使用它。如果小整数就足够了,那么就使用它。使用持久的数据类型,而不是过度的数据类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接