Включить ограничение - PullRequest
       7

Включить ограничение

1 голос
/ 21 апреля 2011

У меня огромная база данных с множеством ограничений, и я обновил некоторые ограничения на отключение данных, и я просто хочу включить их обратно.

Я использовал ниже запрос

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 ]

2 голосов
/ 21 апреля 2011

Выполнение этого «надлежащим образом без каких-либо проблем» займет время. Вы могли бы повысить скорость, пропустив опцию WITH CHECK, но тогда вы получите ненадежных ограничений в вашей БД, поэтому я бы не рекомендовал эту опцию.

1 голос
/ 21 апреля 2011

Использование 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''?'''

В идеале результат таблицы изменений будет захвачен и отправлен обратно.

0 голосов
/ 21 апреля 2011

Необходимо проверить, есть ли у вас индексы по обе стороны ограничения (кстати, хорошая идея при обычных операциях). Чтобы сделать это явно, допустим, что у вас есть две таблицы (tbl_a и tbl_b), между которыми есть ограничение FK (скажем, это col_c). Вам нужен индекс, в котором ведущим столбцом является col_c как для tbl_a, так и для tbl_b, чтобы не приходилось сканировать таблицу, в которой такой индекс отсутствует.

Кроме того, проверка каждого ограничения по отдельности (а не «проверка ограничения всего») даст вам лучшую гранулярность, если вам нужно остановиться посередине.

...