One of the issues I often run into is the need to truncate very large tables. But if there is a foreign key constraint on the table, SQL Server will not allow a truncate, only a delete. This is fine for smaller tables but if the table has millions of rows, we want to do a truncate vs. a delete, as a truncate is minimally logged and much faster. Unfortunately, disabling the constraints is not enough. It has to be dropped. So I put together a script to do this for me.
Save the Definition
The first thing we need to do is document all the foreign keys so we can re-create them later. I do this by getting the constraint definitions from a couple of DMV’s and storing the pertinent data in a temporary table. Note that if for some reason you lost your connection, you would lose this table so you could give some consideration to using a permanent table.
1: SELECT
2: fk.name AS FKName
3: ,OBJECT_NAME(fk.parent_object_id) AS TableName
4: ,OBJECT_NAME(fk.referenced_object_id) AS ReferencesTable
5: ,COL_NAME(fk.parent_object_id,fkc.parent_column_id) AS ConstraintColumn
6: ,COL_NAME(fk.referenced_object_id,referenced_column_id) AS ReferenceColumn
7: INTO #fk
8: FROM sys.foreign_keys fk
9: INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id
10: ORDER BY 1
Drop the Constraints
Now we can use dynamic SQL to drop the constraints
1: DECLARE
2: @FKName sysname
3: ,@TableName sysname
4: ,@ReferencesTableName sysname
5: ,@ConstraintColumn sysname
6: ,@ReferenceColumn sysname
7: ,@SQL NVARCHAR(4000)
8:
9: DECLARE cur CURSOR FOR
10: SELECT FKName, TableName FROM #fk
11: OPEN cur
12: WHILE 1=1
13: BEGIN
14: FETCH NEXT FROM cur INTO @FKName, @TableName
15: IF @@fetch_status !=0
16: BREAK
17:
18: SET @SQL = 'alter table ' + @TableName + ' DROP CONSTRAINT ' + @FKName
19: EXEC dbo.sp_executesql @SQL
20: END
21: CLOSE cur
22: DEALLOCATE cur
23: GO
Truncate the Tables
Using the undocumented stored procedure sp_msforeachtabled we can easily truncate all the tables now.
1: exec sp_MSforeachtable 'truncate table ?'
Re-Create the Constraints
Finally, we use dynamic SQL to re-create the constraints
1: DECLARE
2: @FKName sysname
3: ,@TableName sysname
4: ,@ReferencesTableName sysname
5: ,@ConstraintColumn sysname
6: ,@ReferenceColumn sysname
7: ,@SQL NVARCHAR(4000)
8:
9: DECLARE cur CURSOR FOR
10: SELECT * FROM #fk
11: OPEN cur
12: WHILE 1=1
13: BEGIN
14: FETCH NEXT FROM cur INTO @FKName, @TableName, @ReferencesTableName,
15: @ConstraintColumn, @ReferenceColumn
16: IF @@fetch_status !=0
17: BREAK
18:
19: SET @SQL = 'alter table ' + @TableName + ' ADD CONSTRAINT ' + @FKName +
20: ' FOREIGN KEY(' + @ConstraintColumn + ') REFERENCES '
21: + @ReferencesTableName + '(' + @ReferenceColumn + ')'
22: EXEC dbo.sp_executesql @SQL
23: END
24: CLOSE cur
25: DEALLOCATE cur
26: GO
Finally a quick script to check the final row counts
1: create table #rowcount (tablename varchar(128), rowcnt int)
2:
3: exec sp_MSforeachtable 'insert into #rowcount select ''?'', count(*) from ?'
4:
5: select * from #rowcount order by tablename
6:
7: DROP TABLE #rowcount
8:
This Post Has 4 Comments
I like your solution to truncating tables with foreign keys but it doesn’t work correctly with tables that have complex primary keys. Do you have a fix for that?
This worked great, thank you
Maybe it’s my browser (Edge) — but the FG color = BG color on the code snippets. Everything is “whited-out”. Can’t see anything until you select a block of code.
John, thanks for pointing that out. We have adjusted the HTML…should display properly now.