SQL Server数据库中的IDENTITY类型字段
警告:这个悲惨的故事包含代码异味和糟糕的设计决策以及技术债务的例子。
如果您熟悉SOLID原则,练习TDD并对您的工作进行单元测试, 请勿阅读 。 除非你想要在别人的不幸中幸灾乐祸地笑,并且知道你永远不会为你的继任者留下如此巨大的垃圾堆。
所以,如果你坐得舒服,那么我会开始。
在过去的7个月中,我继承并支持和修复了这个应用程序,这让我留下了一个由6个半月前离开的开发人员的DOOZY。 是的,我开始2周后。
无论如何。 在这个应用程序中,我们有clients
, employees
和visits
表。
还有一个名为AppNewRef
(或类似的东西)的表,它等待它...包含下一个记录ID,用于其他每个表。 因此,可能包含如下数据: -
TypeID Description NextRef
1 Employees 804
2 Clients 1708
3 Visits 56783
当应用程序为Employees
创建新行时,它将在AppNewRef
表中查找,获取值,将该值用于ID,然后更新NextRef
列。 Clients
和Visits
以及使用NextID
所有其他表都存储在此处。
是的,我知道,在这个数据库上没有自动编号的IDENTITY
列。 所有的借口“当它是一个访问应用程序”。 这些ID被保存在(VB6)代码中。 因此,可能有高达2亿1亿4700万条记录。 好的,这似乎工作得很好。 (除了应用程序正在更新并关注锁定/更新等事实,而不是数据库)
因此,我们的用户非常高兴地创建Employees
, Clients
, Visits
等。 Visits ID
一直在稳步增加几十个。 然后出现问题。 我们的客户正在造成数据库损坏,同时创建了多次访问,因为服务器运行良好,应用程序变得无法响应。 所以他们使用任务管理器来杀死应用程序,而不是耐心等待。 授予应用程序似乎锁定。
今年早些时候,开发者Tim(真实姓名,不保护有罪)开始修改代码以分阶段进行批量更新,以便UI保持“响应”。 然后4月来了,他正在通知他(你现在可以想象这个场景,不是吗?),他正在努力完成更新。
四月底和五月初,我们更新了一些客户。 在接下来的几个月中,我们会更新更多。
蒂姆(真名,请记住)和我(在蒂姆离开前两周开始)以及另一位在一周后开始的新开发者看不到,身份证在参观桌上开始向上飞跃。 巨大的,我的意思是一次10000,20000,30000。 有时几十万。
这是一张图表,说明所用ID的快速增长。
11月滚动。 客户致电技术支持部门并报告他出现错误。 我查看错误消息并询问数据库,以便调试代码。 我发现这个价值太长了很久。 我做了一些查询,将信息拖放到Excel中并绘制成图。
我不认为让代码处理任何东西的时间长于ID,这是正确的方法,因为这个应用程序将该ID传递给其他DLL和OCX,并且打破了这些接口,看起来像是一个整体的伤害世界现在不想遇到。
我正在调查的一个潜在想法是尝试修改ID,以便我可以将它们降低到较低的水平。 基本上填补了空白。 使用ROW_NUMBER
函数
我想要做的是在每个具有对这些访问ID的外键引用的表中添加一个新列(不是正确的外键思维,这些约束在此数据库中不存在)。 这个新列可以存储访问ID的旧(当前)值(噢,只是为了混淆事物;在某些表上称为EventID
,在某些表上称为VisitID
)。
然后,对于引用该VisitID
每个其他表,更新为新值。
想法? 建议? T-SQL片段帮助所有人感激地收到。
选项一:
明确约束所有外键关系,并将它们设置为ON UPDATE CASCADE
。
这意味着只要您更改ID,外键就会自动更新。
然后,你只是运行这样的事情...
WITH
resequenced AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY id) AS newID,
*
FROM
yourTable
)
UPDATE
resequenced
SET
id = newID
我没有在年龄这样做,让我忘了,如果它通过具有相同的id值两个记录会导致问题,年年更新。 如果是这样,你可以先做这样的事情......
UPDATE yourTable SET id = -id
选项二:
确保没有任何外键关系是明确定义的。 如果他们是,请注意他们donw并删除它们。
然后做一些像...
CREATE TABLE temp AS
newID INT IDENTITY (1,1),
oldID INT
)
INSERT INTO temp (oldID) SELECT id FROM yourTable
/* Do this once for the table you are re-identifiering */
/* Repeat this for all fact tables holding that ID as a foreign key */
UPDATE
factTable
SET
foreignID = temp.newID
FROM
temp
WHERE
foreignID = temp.oldID
然后重新应用任何现有的外键关系。
这是一个非常可怕的选择。 如果您忘记更新表格,那么您只需将数据保存起来。 但是,你可以给temp
表一个更好的名字,并保持它。
祝你好运。 主可以怜悯你的灵魂。 而蒂姆,如果你曾在黑暗的小巷里见过他。
我会创建一个数字表,它只有一个从1到1的序列,而增量为1的任何max都是很长的,然后更改为visitid获取maxid的逻辑,也许其他人在数字和访问表之间进行正确连接。 然后你可以寻找这个数字的最小值
select min(number) from visits right join numbers on visits.id = numbers.number
这样你就可以填补所有的空白,而不必改变任何其他的表格。
但我只是重做整个数据库。
链接地址: http://www.djcxy.com/p/11429.html