启用约束

时间:2011-04-21 16:39:01

标签: sql sql-server tsql sql-server-2000

我有一个包含许多约束的庞大数据库,我已经更新了一些数据禁用约束,我只是想重新启用它们。

我使用了以下查询

EXEC sp_msforeachtable 'ALTER TABLE MyTable NOCHECK CONSTRAINT all' 
exec sp_msforeachtable @command1='print ''MyTable''', @command2='ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT all'

但是当我运行启用查询时,由于数据量巨大,需要很长时间。这需要1个多小时。

我只想以正确的方式快速启用它而不会出现任何问题。

请指导我如何克服这个问题。

3 个答案:

答案 0 :(得分:2)

“没有任何问题的正确方式”这样做需要时间。您可以通过省略WITH CHECK选项来提高速度,但最终会在数据库中使用untrusted constraints,因此我不建议使用该选项。

答案 1 :(得分:1)

使用sp_msforeachtable运行语句顺序。最有可能通过几个线程传播的东西将加速这个过程。使用Service Broker,可以在SQL代码中完成。

(下面是从内存中编写的代码,我没有可用于测试它的SQL Server。因此可能存在一些错误。每当我有服务器可用时,我都会更新。)

首先创建激活程序

  CREATE PROC p_enable_constraints
  AS
     DECLARE @handle UNIQUEIDENTIFIER
           , @message sysname
           , @sql nvarchar(max)

     WHILE 1=1
       BEGIN
         BEGIN TRAN
         WAITFOR ( RECEIVE TOP(1) @handle = conversation_handle,
                              @message = message_body
                   FROM ConstraintQueueReceive), TIMEOUT 1000;
        IF @@rowcount = 0
          begin
            rollback
            break;
          end

        set @sql = N'ALTER TABLE ' + quotename(@message) + N' WITH CHECK CONSTRAINT ALL'
        exec (@sql)
        if @@error <> 0
          begin
            rollback tran
            break
          end 
        COMMIT TRANSACTION
      END
    RETURN(0)
   GO

设置队列和服务以发送和接收消息

  CREATE QUEUE ConstraintQueueSend
  CREATE SERVICE ConstraintServiceSend

  CREATE QUEUE ConstraintQueueReceive 
    WITH STATUS = ON, ACTIVATION (PROCEDURE_NAME = p_enable_constraints
                                 , MAX_QUEUE_READERS = 8
                                 , EXECUTE AS SELF);

  CREATE SERVICE [ConstraintServiceReceive] ON QUEUE ConstraintQueueReceive 

现在创建一个为每个表提交消息的过程

  CREATE PROC p_submit_enable_constraints_message @object sysname
  AS
    DECLARE @handle UNIQUEIDENTIFIER;
    DECLARE @message sysname;

    BEGIN TRANSACTION;
    BEGIN DIALOG @handle FROM SERVICE [ConstraintServiceSend] 
                           TO SERVICE [ConstraintServiceReceive]
    WITH ENCRYPTION = OFF;
    SEND ON CONVERSATION @handle (@object);

    COMMIT TRANSACTION;

    END CONVERSATION @handle
    GO

最后,我们可以调用该过程将其提交到队列中。

   EXEC sp_msforeachtable 'EXEC p_submit_enable_constraints_message N''?'''

理想情况下,会捕获并发回alter table的结果。

答案 2 :(得分:0)

要检查的一件事是你是否在约束的两边都有索引(在正常操作期间,btw是一个好主意)。为了明确这一点,假设你有两个表(tbl_a和tbl_b)之间有一个FK约束(让我们说它是col_c)。你需要一个索引,其中tbl_a和tbl_b上的前导列是col_c,这样它就不必对没有这种索引的表进行表扫描。

此外,单独检查每个约束(而不是执行“检查约束全部”)将为您提供更好的粒度,如果您需要在中间停止。