为什么不支持删除列上的Identity属性


11

我读过,在SQL Server 2000之后,删除了“取消身份”身份列的功能。而且这是“通过设计”(不仅仅是缺少的功能)。

这是我在博客上找到的示例。它涉及更新系统表。(并且该功能在SQL Server 2000之后被删除。)我知道通过系统表执行此操作不是一个好主意。我只是想知道为什么没有其他功能可以做到这一点。

解决此问题将使我付出大量工作。(在无法停机的环境中将数亿行复制到新表中。)

所以我想问“为什么”。

Sql Server 2005和更高版本中发生了什么更改,这使这件事变得不好了?还是总是不好,只是没有被锁定?

将身份列再次设为普通列会违反什么“最佳实践”(或类似原则)?

-

更新以回答“为什么要这样做”的请求:
这是一个非常高级的摘要:我将开始向表中添加分区。(这样我就可以存档/清除旧数据。)这很容易。但是我有时需要将记录移到另一个分区,以免被删除(当一个分区用于归档/删除时)。(我的分区列增加了2,以便始终有空间将行移动到其他分区。)

但是,如果分区列是一个标识列,那么我必须删除并重新插入该值(无法更新标识列的值)。这会导致复制问题。

所以我想使用序列而不是标识列。但是在大型数据库上,这种切换非常困难。

Answers:


22

您的问题本质上是:

为什么我不能再做一开始就不应该做的冒险的事情?

该问题的答案基本上无关紧要(尽管您可以在这些Connect项中看到一些Microsoft注释,要求该功能:#294193#252226)。为了完整起见,我的提要是:删除标识属性的能力是首先具有破坏系统表的能力的意外副作用。不应以多种方式使用此功能,通常会带来非常严重的后果,因此将其删除。这是一个未经证明,不受支持的系统表黑客。不会删除更改系统表中数据的功能,因为Microsoft不再希望您侵入以身分身份的列之列,而删除该功能是因为处理系统表具有极大的风险。删除IDENTITY属性本身并不是专门针对性的功能删除,即使在有可能的古代,我也永远不会完全信任这种方法。

也就是说,我们如何回答这个问题呢?

如何在停机时间最少或没有停机的情况下删除列的IDENTITY属性?

您可以轻松地使用ALTER TABLE ... SWITCH这项技术,我肯定是我首先从我们自己的Paul White那里学习的,在Connect#252226的变通办法中。简单的例子,给出这个简单的表:

CREATE TABLE dbo.Original
(
  ID INT IDENTITY(1,1) PRIMARY KEY,
  name SYSNAME
);
GO

INSERT dbo.Original(name) VALUES(N'foo'),(N'bar');
GO

SELECT * FROM dbo.Original;
GO

结果:

ID  name
--  ----
1   foo
2   bar

现在,让我们创建一个影子表,并切换到它,然后删除旧表,重命名新表,然后恢复正常活动:

CREATE TABLE dbo.New
(
  ID INT PRIMARY KEY,
  name SYSNAME
);
GO

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
  ALTER TABLE dbo.Original SWITCH TO dbo.New;
  DROP TABLE dbo.Original;
  EXEC sys.sp_rename N'dbo.New', N'Original', 'OBJECT';
COMMIT TRANSACTION;
GO

INSERT dbo.Original(ID,name) VALUES(3,N'splunge');
UPDATE dbo.Original SET ID = 6 WHERE ID = 1;
GO

SELECT * FROM dbo.Original;
GO

结果:

ID  name
--  -------
2   bar
3   splunge
6   foo

现在清理:

DROP TABLE dbo.Original;

这仅是元数据操作,没有数据移动,并且仅在更新元数据时阻止其他用户。但是,不可否认,这是一个非常简单的例子。如果您有外键或正在使用其他功能(例如复制,更改数据捕获,更改跟踪等),则可能需要在进行此更改之前禁用或删除其中一些功能(我尚未测试所有组合)。特别是对于外键,请参阅此技巧该技巧显示了如何生成脚本以删除并重新创建所有(或选定的)外键约束。

此外,您将需要更新应用程序代码,以免SQL Server填充此列,并检查可能取决于列顺序或它们需要指定的列的所有insert或select语句。通常,对于此表的任何提及,我都会复制整个代码库。

另请参阅Itzik Ben-Gan的脚本(来源:此古老的文章),以了解另一种处理此问题的方法,但是这里涉及数据移动,因此它不能满足“无停机时间或最少停机时间”的要求。


3
我想鼓励任何人来投票赞成两个连接项。实现ALTER COLUMN功能以打开或关闭标识布尔值有多困难?痛苦地工作。
usr

我不得不承认,出于某种原因,我认为这..SWITCH..仅适用于已定义至少一个分区的表。
RBarryYoung 2015年

只需添加SWITCH就不需要企业版,尽管表分区确实需要。
丹·古兹曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.