Reputation: 127
I have a huge database with many constraints and I have updated some data disabling constraint and I just want to enable them back.
I have used below query
EXEC sp_msforeachtable 'ALTER TABLE MyTable NOCHECK CONSTRAINT all'
exec sp_msforeachtable @command1='print ''MyTable''', @command2='ALTER TABLE MyTable WITH CHECK CHECK CONSTRAINT all'
But when I run the enable query it takes a long time due to huge volume of data. It take more than 1 hour.
I just want to enable it quickly in the proper way without having any issues.
Please guide me how to overcome this issue.
Upvotes: 1
Views: 1310
Reputation: 11908
Using sp_msforeachtable runs the statements sequential. Most likely spreading things out over a few threads will speed up the process a lot. With Service Broker this can be done in SQL Code.
(Below is code written from memory, I have no SQL Server available to test this on. So there might be some bugs in it. I will update whenever I have a Server available.)
First create an activation procedure
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
Set up the Queues and Services to send and receive messages
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
Now create a procedure to submit a message for each table
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
Finally we can call the procedure to submit this to the queue.
EXEC sp_msforeachtable 'EXEC p_submit_enable_constraints_message N''?'''
Ideally the result of the alter table is captured and sent back.
Upvotes: 1
Reputation: 32707
One thing to check is if you have indexes on both sides of the constraint (a good idea during normal operations, btw). To make this explicit, let's say that you have two tables (tbl_a and tbl_b) that have a FK constraint between them (let's say it's col_c). You'd want an index where the leading column is col_c on both tbl_a and tbl_b so that it doesn't have to table scan the table that doesn't have such an index.
Also, checking each constraint individually (rather than doing a "check constraint all") will give you better granularity should you need to stop in the middle.
Upvotes: 0
Reputation: 135818
Doing it "proper way without having any issue" is going to take time. You could improve the speed by omitting the WITH CHECK
option, but then you'll end up with untrusted constraints in your DB, so I would not recommend that option.
Upvotes: 3