2017-06-18 61 views
1

使用的版本:重新播种的大型SQL表

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行),我从另一个数据库移动。 它以[id]列作为标准int列转移,而不是它的关键&种子列。 当试图编辑领域成为一个标识规范,以种子值,它的错误,并给了我这个错误:

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

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

感谢

UPDATE:

表结构:

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 
+0

是你在C#或VB中使用SqlCommand还是直接使用SSMS? –

+2

请勿使用SSMS UI更改表模式。使用T-SQL脚本可以更高效地完成此操作,如果您需要帮助,请将现有表的DDL过帐。 –

+0

谢谢你们。是的,我正在使用SSMS。我已经在问题中粘贴了“CREATE”代码。此表现在重约2.4GB ......谢谢。 – kneidels

回答

2

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


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

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

ssms timeout

当然,你可以更改SSMS此设置,并增加超时,但有一个更好的方法。

  1. 简单/偷懒的办法

使用SSMS GUI更改列定义,但随后而不是单击“保存”,点击“生成改变脚本”表设计器。

ssms generate change script

那么这个脚本保存到一个文件,并查看GUI运行幕后生成的T-SQL代码。

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

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

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

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

ssms run


  • 智能和快速的方式,进行详细在此answer由Justin格兰特描述的事情。
  • 主要想法是使用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, 
    
    +0

    谢谢你的详细解答。我将该版本添加到OP。这是我在尝试运行解决方案#2时得到的错误:'ALTER TABLE SWITCH语句失败。表'dbo.NEW_tblEmailsS​​ent'具有聚簇索引'PK_tblEmailsS​​ent',而'dbo.tblEmailsS​​ent'表没有聚簇索引。' – kneidels

    +0

    那么,错误消息是明确的 - 一个表有一个聚簇索引,另一个没有聚簇索引。确保新表的定义与现有表完全相同,但“IDENTITY”部分除外。使用SSMS来生成'CREATE TABLE'脚本。 –

    +0

    嗯...得到'小心:更改对象名称的任何部分可能会中断脚本和存储过程。' – kneidels