重新播种大型SQL表

时间:2017-06-18 19:56:39

标签: sql sql-server sql-server-2008-r2

使用版本:

Microsoft SQL Server 2008 R2 (SP3-OD) (KB3144114) - 10.50.6542.0 (Intel X86) 
Feb 22 2016 18:12:09 
Copyright (c) Microsoft Corporation
Standard Edition on Windows NT 5.2 <X86> (Build : )

我有一张沉重的桌子(135K行),我从另一个DB移动了。 它转移时[id]列是标准int列,而不是关键字&amp;种子栏。 当尝试编辑该字段以成为身份规范时,使用种子值,其错误输出并给我这个错误:

Execution Timeout Expired.  
The timeout period elapsed prior to completion of the operation...

我甚至尝试删除该列,稍后尝试重新创建它,但我得到同样的问题。

由于

更新

表格结构:

CREATE TABLE [dbo].[tblEmailsSent](
    [id] [int] IDENTITY(1,1) NOT NULL,  -- this is what it should be. currently its just an `[int] NOT NULL`
    [Sent] [datetime] NULL,
    [SentByUser] [nvarchar](50) NULL,
    [ToEmail] [nvarchar](150) NULL,
    [StudentID] [int] NULL,
    [SubjectLine] [nvarchar](200) NULL,
    [MessageContent] [nvarchar](max) NULL,
    [ReadStatus] [bit] NULL,
    [Folder] [nvarchar](50) NULL,
 CONSTRAINT [PK_tblMessages] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

1 个答案:

答案 0 :(得分:3)

我认为您的问题与Adding an identity to an existing column重复。上面的问题有answer,应该适合您的情况。我将在下面重现其重要部分。

但在此之前,让我们澄清为什么你会看到超时错误。

您正尝试将IDENTITY属性添加到现有列。你正在使用SSMS GUI。一个简单的ALTER COLUMN语句不能这样做,即使可以,SSMS也会生成一个创建新表的脚本,将数据复制到新表中,删除旧表并将新表重命名为旧表名称。当您通过SSMS GUI执行此操作时,它会以30秒的预定义超时运行其脚本。

ssms timeout

当然,您可以在SSMS中更改此设置并增加超时,但有更好的方法。

  1. 简单/懒惰的方式
  2. 使用SSMS GUI更改列定义,但不是单击“保存”,而是单击表设计器中的“生成更改脚本”。

    ssms generate change script

    然后将此脚本保存到文件中,并查看GUI在场景后运行的生成的T-SQL代码。

    您将看到它创建了一个包含所需模式的临时表,复制数据,重新创建外键和索引,删除旧表并重命名新表。

    脚本本身通常是正确的,但要密切关注其中的事务。由于某种原因,SSMS通常不会对整个操作使用单个事务,而是使用多个事务。我建议您手动查看脚本,确保顶部只有一个BEGIN TRANSACTION,最后一个COMMIT。您不希望最终使用半完成操作,例如,删除所有索引和外键的表。

    如果是一次性操作,对您来说就足够了。你的桌子只有2.4GB,所以可能需要几分钟,但不应该是几个小时。

    如果您在SSMS中自己运行T-SQL脚本,则默认情况下不会超时。如果花费太长时间,你可以自己停止。

    ssms run

    1. Justin Grant在此answer中详细介绍了实现这一目标的快捷方式。
    2. 主要思想是使用ALTER TABLE...SWITCH语句使更改仅触及元数据而不触及表格的每一页。

      BEGIN TRANSACTION;
      
      -- create a new table with required schema
      CREATE TABLE [dbo].[NEW_tblEmailsSent](
          [id] [int] IDENTITY(1,1) NOT NULL,
          [Sent] [datetime] NULL,
          [SentByUser] [nvarchar](50) NULL,
          [ToEmail] [nvarchar](150) NULL,
          [StudentID] [int] NULL,
          [SubjectLine] [nvarchar](200) NULL,
          [MessageContent] [nvarchar](max) NULL,
          [ReadStatus] [bit] NULL,
          [Folder] [nvarchar](50) NULL,
       CONSTRAINT [PK_tblEmailsSent] PRIMARY KEY CLUSTERED 
      (
          [id] ASC
      )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
      ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
      
      -- switch the tables
      ALTER TABLE [dbo].[tblEmailsSent] SWITCH TO [dbo].[NEW_tblEmailsSent];
      
      -- drop the original (now empty) table
      DROP TABLE [dbo].[tblEmailsSent];
      
      -- rename new table to old table's name
      EXEC sp_rename 'NEW_tblEmailsSent','tblEmailsSent';
      
      COMMIT;
      

      新表具有IDENTITY属性后,通常应将当前标识值设置为表中实际值的最大值。如果不这样做,插入表中的新行将从1开始。

      一种方法是在切换表后运行DBCC CHECKIDENT

      DBCC CHECKIDENT('dbo.tblEmailsSent')
      

      或者,您可以在表定义中指定新种子:

      CREATE TABLE [dbo].[NEW_tblEmailsSent](
          [id] [int] IDENTITY(<max value of id + 1>, 1) NOT NULL,