我不认为她对ID通胀的原因是正确的(可以回答这个问题的同事是休假,所以我们不确定),但我们假设她是.她说她讨厌使用bigint列,并且她希望我们停止自动增加ID列并编写服务器端代码,选择第一个“未使用”整数并将其用作ID.
我是一名计算机科学研究生,缺乏实践经验,担任初级开发人员.她拥有多年管理我们所有组织数据库和设计大部分数据库的经验.我认为在这种情况下她是不正确的,一个bigint ID是没有什么可怕的,并且模仿DBMS功能的反模式.但我还不相信我的判断.
每个职位的支持和反对意见是什么?如果我们使用bigint会发生什么不好的事情,重新发明车轮自动增量功能的危险是什么?有没有第三种解决方案比任何一种都好?她的理由是什么可以避免ID面值的膨胀?我也有兴趣听到实用的原因 – 也许bigint ID在理论上起作用,但在实践中会引起头疼吗?
预计应用程序不会处理大量数据.我怀疑它将在未来几年内达到10000个实际记录.
如果它有任何区别,我们正在使用Microsoft sql服务器.该应用程序是用C#编写的,并使用Linq to sql.
更新
谢谢,我发现现有的答案和评论很有趣.但是我害怕你误解了我的问题,所以它们包含我想知道的东西.
我并不真正关心高ID的真正原因.如果我们无法自己找到它,我可以问一个不同的问题.我感兴趣的是了解这种情况下的决策过程.为此,请假设该应用程序将每天写入1000条记录,然后删除其中的9999条记录.我几乎可以肯定事实并非如此,但这是我的老板在提出要求时所相信的.那么,在这些假设的情况下,使用bigint或编写我们自己的代码来分配ID(以重用已经删除的记录的ID的方式,以确保没有间隙)的利弊是什么?
至于实际原因,我强烈怀疑这是因为我们曾经编写过代码来从另一个数据库导入数据,作为一个概念的证明,即以后的迁移可以在一定程度上完成.我认为我的同事在导入过程中实际创建了数千条记录,后来删除了它们.我必须确认这是否真的如此,但如果确实如此,甚至不需要采取行动.
解决方法
一个简单的INT字段可以容纳最多2,147,483,647的值.您实际上可以在-2,648处开始标识值,从而提供完整的32位值. 40亿个不同的价值观.我非常怀疑你是否会耗尽价值.假设您的应用程序为每个添加的实际行消耗了1,000个值,您需要每天创建近12,000行,以便在6个月内用完ID,假设您将IDENTITY值设置为0,并使用INT.如果您使用的是BIGINT,那么如果您每天写入12,每行消耗1,000个“值”,则在耗尽值之前必须等待2100万个世纪.
说了这么多,如果你想使用BIGINT作为身份字段数据类型,那肯定没有错.这将为您提供所有意图和目的,使用无限的价值供应.在现代64位硬件上,INT和BIGINT之间的性能差异几乎不存在,并且非常优于使用NEWID()生成GUID的实例.
如果您想为ID列管理自己的值,可以创建一个密钥表,并使用此问题的答案中显示的方法之一提供一种非常灵活的方法:Handling concurrent access to a key table without deadlocks in SQL Server
假设您正在使用sql Server 2012,另一个选项是使用SEQUENCE对象来获取列的ID值.但是,您需要将序列配置为不缓存值.例如:
CREATE SEQUENCE dbo.MySequence AS INT START WITH -2147483648 INCREMENT BY 1 NO CACHE;
在回答老板对“高”数字的负面看法时,我会说它有什么区别?假设您使用带有IDENTITY的INT字段,您实际上可以在2147483647处启动IDENTITY并将值“递增”-1.这将使32位数为4字节时使用的内存消耗,性能或磁盘空间完全没有差别,无论它是0还是2147483647.当存储在32位有符号INT字段中时,二进制中的0为00000000000000000000000000000000 . 2147483647是01111111111111111111111111111111 – 两个数字在内存和磁盘上都占用相同的空间量,并且两者都需要精确相同数量的cpu操作来处理.正确设计应用程序代码比忽略存储在关键字段中的实际数字要重要得多.
您询问了(a)使用大容量ID列(例如BIGINT)或(b)滚动您自己的解决方案以防止ID间隙的利弊.要回答这些问题:
> BIGINT而不是INT作为相关列的数据类型.使用BIGINT需要双倍的存储量,包括磁盘本身和内存中的存储量.如果列是所涉及的表的主键索引,则附加到表的每个非聚簇索引也将存储BIGINT值,其大小是INT的两倍,同样是内存中和磁盘上的. sql Server将数据存储在8KB页面的磁盘上,其中每个“页面”的“行”数取决于每行的“宽度”.因此,例如,如果您有一个包含10列的表,每个列都是一个INT,那么您每页最多可以存储160行.如果那些列代替BIGINT列,则每页只能存储80行.对于具有非常多行的表,这显然意味着对于任何给定数量的行,在该示例中读取和写入表所需的I / O将是双倍的.当然,这是一个非常极端的例子 – 如果你有一个由一个INT或BIGINT列和一个NCHAR(4000)列组成的行,你(简单地)每页只能获得一行,无论你是否使用了INT或者是BIGINT.在这种情况下,它不会产生太大的明显差异.
>滚动您自己的方案以防止ID列中的间隙.您需要编写代码,以确定要使用的“下一个”ID值与发生在表中的其他操作不冲突. SELECT TOP(1)[ID] FROM [schema].[table]的东西天真地浮现在脑海中.如果有多个actor同时尝试向表中写入新行怎么办?两个演员可以很容易地获得相同的值,从而导致写冲突.解决此问题需要序列化对表的访问,从而降低性能.有很多关于这个问题的文章;我将把它留给读者来搜索该主题.
这里的结论是:您需要了解您的需求并正确估计行数,行宽以及应用程序的并发性要求.像往常一样,它取决于它.