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:
Justin Dearing 1:35 pm on February 5, 2011 Permalink |
I guess my only comment is the forth point should be tuned based on needs of the hiring shop. I worked for a place that was deeply invested in XML on all tiers, but had no need to use SQL’s internal reporting services. A consulting house would need a jack of all trades.
As far as knowing the internals first, and T-SQL second I agree. As a programmer who has to wear the DBA hat, I never say “I wish a real DBA could show me how to use @TSQL_KEYWORD” and I can read a query plan and know if it looks ugly. However, beyond “it normalized”, columns are as small as possible and “CI SEEK > NCI SEEK > IX SCAN > TABLE SCAN” I don’t know what to do.
Randy Knight 10:21 pm on February 5, 2011 Permalink |
Good points. My thought on bullet 4 is that anybody who claims to know SQL Server should at least know what each of those things are. And then you could delve into expertise on a given feature depending on needs.