Datawarehouse-tests makkelijker maken met slim tabelbeheer
Als je een datawarehouse test, is het vaak lastig om grote datasets goed te beheren. Vaak moet je tabellen terugzetten naar een schone toestand, zodat je testomgevingen gelijk blijven. De efficiëntste manier om een tabel leeg te maken is het SQL-commando TRUNCATE TABLE. Maar dat commando werkt niet zomaar als er foreign key constraints zijn. Hieronder staat een oplossing die de constraints tijdelijk uitschakelt, de tabellen leegmaakt en daarna de constraints terugzet. Zo blijft je datamodel heel.
Waarom deze methode?
In een datawarehouse hangen tabellen meestal aan elkaar via relaties die foreign key constraints afdwingen. Als je testomgevingen klaarzet:
- Moet je vaak de data terugzetten en de tabelstructuur houden.
- Is TRUNCATE TABLE beter dan DELETE voor de performance: het is sneller en zet identity-velden automatisch terug.
- Mislukt direct leegmaken als een foreign key naar een tabel verwijst.
Het script hieronder automatiseert dit: het bewaart de constraints, dropt ze tijdelijk, maakt de tabellen leeg en zet de constraints terug. Zo zet je testomgevingen terug zonder de integriteit van het databaseschema te verliezen.
Hoe het script werkt
- Constraints bewaren:
- Het script zoekt alle foreign key constraints dynamisch op via de system views van SQL Server.
- Het bewaart de tabelnamen, de namen van de constraints en hun definities in een tijdelijke tabel.
- Constraints droppen:
- Het dropt de constraints van de tabellen. De referentiële integriteit staat dan tijdelijk uit.
- Tabellen leegmaken:
- Met TRUNCATE TABLE verdwijnt alle data in het opgegeven schema snel, en de identity-velden gaan terug naar het begin.
- Constraints terugzetten:
- Het maakt de constraints opnieuw aan met de definities uit de tijdelijke tabel.
Het script
Hieronder staat het complete script. Het beheert de foreign key constraints, maakt de tabellen leeg en zet de constraints terug.
DECLARE @SchemaName NVARCHAR(128) = 'your_schema_name';DECLARE @SQL NVARCHAR(MAX);
-- Step 1: Create a temporary table to store constraintsIF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL DROP TABLE #ForeignKeys;
CREATE TABLE #ForeignKeys ( TableName NVARCHAR(128), ConstraintName NVARCHAR(128), ForeignKeyDefinition NVARCHAR(MAX));
-- Step 2: Populate the temporary table with foreign keys in the schemaINSERT INTO #ForeignKeys (TableName, ConstraintName, ForeignKeyDefinition)SELECT QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) AS TableName, fk.name AS ConstraintName, 'ALTER TABLE ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) + ' FOREIGN KEY (' + STUFF(( SELECT ', ' + QUOTENAME(c.name) FROM sys.columns c INNER JOIN sys.foreign_key_columns fkc ON fkc.parent_column_id = c.column_id AND fkc.parent_object_id = c.object_id WHERE fkc.constraint_object_id = fk.object_id FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ') REFERENCES ' + QUOTENAME(SCHEMA_NAME(rt.schema_id)) + '.' + QUOTENAME(rt.name) + '(' + STUFF(( SELECT ', ' + QUOTENAME(rc.name) FROM sys.columns rc INNER JOIN sys.foreign_key_columns rfkc ON rfkc.referenced_column_id = rc.column_id AND rfkc.referenced_object_id = rc.object_id WHERE rfkc.constraint_object_id = fk.object_id FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')' + CASE WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE' WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL' ELSE '' ENDFROM sys.foreign_keys fkINNER JOIN sys.tables t ON fk.parent_object_id = t.object_idINNER JOIN sys.tables rt ON fk.referenced_object_id = rt.object_idWHERE SCHEMA_NAME(t.schema_id) = @SchemaName;
-- Step 3: Drop all foreign keys using XML-based string concatenationSELECT @SQL = (SELECT 'ALTER TABLE ' + TableName + ' DROP CONSTRAINT ' + QUOTENAME(ConstraintName) + ';' + CHAR(13) FROM #ForeignKeys FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
IF @SQL IS NOT NULL EXEC sp_executesql @SQL;
-- Step 4: Truncate all tables in the schema in reverse dependency orderSELECT @SQL = (SELECT 'TRUNCATE TABLE ' + QUOTENAME(SCHEMA_NAME(t.schema_id)) + '.' + QUOTENAME(t.name) + ';' + CHAR(13) FROM sys.tables t WHERE SCHEMA_NAME(t.schema_id) = @SchemaName ORDER BY t.create_date DESC FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
IF @SQL IS NOT NULL EXEC sp_executesql @SQL;
-- Step 5: Restore the foreign keys using XML-based string concatenationSELECT @SQL = (SELECT ForeignKeyDefinition + CHAR(13) FROM #ForeignKeys FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)');
IF @SQL IS NOT NULL EXEC sp_executesql @SQL;
-- CleanupDROP TABLE #ForeignKeys;
PRINT 'All tables have been truncated, and constraints have been restored.';Conclusie
Dit script automatiseert een lastige klus: tabellen leegmaken terwijl je de foreign key constraints beheert. Je datawarehouse krijgt een schone toestand en het schema blijft heel. Met TRUNCATE TABLE, het bewaren en terugzetten van de constraints en het terugzetten van de identity-velden handel je ook de meest ingewikkelde databaseschema’s snel af.
Deze oplossing is erg handig voor datawarehouse-tests, of voor elke situatie waarin je sleutels en constraints tijdelijk moet omzeilen en de structuur toch stevig moet blijven. Test het in je eigen omgeving en maak je tabelbeheer vandaag nog eenvoudiger!
Veelgestelde vragen
Waarom mislukt TRUNCATE TABLE als er foreign keys zijn in SQL Server?
Direct leegmaken mislukt als een foreign key naar de tabel verwijst. Je moet eerst de constraints verwijderen, dan de tabellen leegmaken en daarna de constraints opnieuw aanmaken.
Hoe maak ik alle tabellen in een schema leeg en behoud ik de foreign keys?
Het script bewaart alle definities van de foreign keys in een tijdelijke tabel, dropt de constraints, maakt elke tabel in het schema leeg met TRUNCATE en maakt de constraints opnieuw aan vanuit de bewaarde definities.
Waarom gebruik ik TRUNCATE TABLE en geen DELETE om testdata terug te zetten?
TRUNCATE TABLE is sneller dan DELETE. Het zet identity-velden ook automatisch terug. Zo krijg je een schone, gelijke beginsituatie om een datawarehouse te testen.
Hoe vindt het script de foreign keys in SQL Server?
Het leest de system views van SQL Server, zoals sys.foreign_keys en sys.foreign_key_columns. Per foreign key bewaart het de tabelnaam, de naam van de constraint en de volledige ALTER TABLE-definitie in een tijdelijke tabel.
Welke tabellen maakt het truncate-script leeg?
Alle tabellen in één schema. Je zet de naam van het schema in de variabele @SchemaName bovenaan het script. Alleen de foreign keys en tabellen in dat schema worden aangeraakt.
Reacties
Gerelateerde blogs
Sneller laden van AS400 naar SQL Server: één kolom per rij
Microsoft MDS end of life: je opties vóór 2028
Datawarehouse en datamart - lege strings of NULL-waarden?