{"id":3079,"date":"2012-11-26T19:09:41","date_gmt":"2012-11-26T19:09:41","guid":{"rendered":"http:\/\/craftydba.com\/?p=3079"},"modified":"2012-11-26T20:09:21","modified_gmt":"2012-11-26T20:09:21","slug":"deleting-large-data","status":"publish","type":"post","link":"https:\/\/craftydba.com\/?p=3079","title":{"rendered":"Deleting Large Data"},"content":{"rendered":"<p><a href=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/caution-oversized-data.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/caution-oversized-data-300x141.jpg\" alt=\"\" title=\"caution-oversized-data\" width=\"300\" height=\"141\" class=\"alignleft size-medium wp-image-3114\" srcset=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/caution-oversized-data-300x141.jpg 300w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/caution-oversized-data.jpg 425w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Most of the time, the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms190925.aspx\">transaction log<\/a> is your friend since it can be used for a point in time recovery.  However, when deleting large amounts of data from a database, it can be your enemy.  I will be reviewing <b>THREE<\/b> different TSQL patterns to delete data.  <\/p>\n<p>Today, we will be using the MATH database that contains prime numbers from 2 to 6 million.  I will post the actual files on this article so that they can be detached and reattached as needed for each test.<\/p>\n<p>We need to remove the foreign key constraint before we can delete data from the primary table we are deleting from &#8211; [TBL_PRIMES].<\/p>\n<pre><span style=\"color: #008000; font-size: small;\">-- Select correct db\r\nUSE [MATH]\r\nGO\r\n\r\n-- Remove unwanted constraint\r\nALTER TABLE [dbo].[TBL_TOP_500_PRIMES] DROP CONSTRAINT [FK_TBL_PRIMES]\r\nGO\r\n<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>The <b>FIRST<\/b> design pattern is good for small amounts of data.  On the other hand, it will lead to rampart log growth if you are not careful. Since the delete occurs inside a transaction, it can be rolled back if we do not remove the correct amount of data.  This is great for preventing unwanted deletions.<\/p>\n<p><u>Algorithm<\/u><br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;Get count of matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;BEGIN TRAN (start a T-SQL transaction).<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;DELETE matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;COMMIT or ROLLBACK transaction.<\/p>\n<pre><span style=\"color: #008000; font-size: small;\">--\r\n-- Delete inside a transaction\r\n--\r\n\r\n\r\n-- Get before info\r\nsp_helpdb [MATH]\r\nGO\r\n\r\n-- Get count of records\r\nSELECT COUNT(*) AS Total FROM [MATH].[dbo].[TBL_PRIMES];\r\nGO\r\n\r\n-- Use transaction 2 delete\r\nBEGIN TRAN;\r\nDELETE FROM [MATH].[dbo].[TBL_PRIMES];\r\n-- ROLLBACK;\r\n-- COMMIT;\r\n\r\n-- Get after info\r\nsp_helpdb MATH\r\nGO\r\n<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>The before image of the database shows a transaction log file size of 32 MB.<\/p>\n<p><a href=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-before-pattern1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-before-pattern1.jpg\" alt=\"\" title=\"sp-helpdb-math-before-pattern1\" width=\"1253\" height=\"326\" class=\"alignleft size-full wp-image-3103\" srcset=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-before-pattern1.jpg 1253w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-before-pattern1-300x78.jpg 300w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-before-pattern1-1024x266.jpg 1024w\" sizes=\"auto, (max-width: 1253px) 100vw, 1253px\" \/><\/a><\/p>\n<p>The after image of the database shows a transaction log file size of 196 MB.<\/p>\n<p><a href=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-after-pattern1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-after-pattern1.jpg\" alt=\"\" title=\"sp-helpdb-math-after-pattern1\" width=\"1256\" height=\"350\" class=\"alignleft size-full wp-image-3104\" srcset=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-after-pattern1.jpg 1256w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-after-pattern1-300x83.jpg 300w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/sp-helpdb-math-after-pattern1-1024x285.jpg 1024w\" sizes=\"auto, (max-width: 1256px) 100vw, 1256px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>The <b>SECOND<\/b> design pattern is great for large amounts of data.  It uses the fact that the transaction log will be truncation upon a backup.  This applies to both the FULL and BULK LOGGED recovery models. A while loop is used to delete 10 K of records per batch until there a no more records to delete.<\/p>\n<p><u>Algorithm<\/u><br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;Make sure we are not in SIMPLE recovery mode.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;Get count of matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;WHILE there are matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DELETE matching records in 10 K batch.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BACKUP LOG to disk (truncate log)<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<pre><span style=\"color: #008000; font-size: small;\">--\r\n-- Delete in batches w\/ log backup in FULL recovery mode\r\n--\r\n\r\n-- Select correct db\r\nUSE [MATH]\r\nGO\r\n\r\n-- Set to full mode\r\nALTER DATABASE [MATH] SET RECOVERY FULL;\r\nGO\r\n\r\n-- Get count of records\r\nSELECT COUNT(*) AS Total FROM [MATH].[dbo].[TBL_PRIMES];\r\nGO\r\n\r\n-- Delete in batches\r\nDECLARE @VAR_ROWS INT = 1;\r\nDECLARE @VAR_CNT INT = 1;\r\nDECLARE @VAR_FILE VARCHAR(128) = '';\r\n\r\nWHILE (@VAR_ROWS > 0)\r\nBEGIN\r\n\tDELETE TOP (10000) FROM [MATH].[dbo].[TBL_PRIMES]; \r\n\tSET @VAR_ROWS = @@ROWCOUNT;\r\n\tSET @VAR_FILE = 'C:\\MSSQL\\BACKUP\\MATH-' + REPLACE(STR(@VAR_CNT, 3, 0), ' ', '0') + '.TRN';\r\n        BACKUP LOG [MATH] TO DISK = @VAR_FILE;\r\n\tSET @VAR_CNT = @VAR_CNT + 1;\r\nEND;\r\nGO\r\n<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>The <b>THIRD<\/b> and last design pattern is exceptional for large amounts of data.  Since we are putting the database into a simple recovery model, I suggest performing a full back up before and after the deletion.<\/p>\n<p><u>Algorithm<\/u><br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;Make sure we are in SIMPLE recovery mode.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;Get count of matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;While there are matching records.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;{<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Delete matching records in 10 K batch.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Use checkpoint to truncate log.<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;}<\/p>\n<pre><span style=\"color: #008000; font-size: small;\">--\r\n-- Delete in batches in SIMPLE recovery mode\r\n--\r\n\r\n-- Select correct db\r\nUSE [MATH]\r\nGO\r\n\r\n-- Set to simple mode\r\nALTER DATABASE [MATH] SET RECOVERY SIMPLE;\r\nGO\r\n\r\n-- Get count of records\r\nSELECT COUNT(*) AS Total FROM [MATH].[dbo].[TBL_PRIMES];\r\nGO\r\n\r\n-- Delete in batches\r\nDECLARE @VAR_ROWS INT = 1;\r\nWHILE (@VAR_ROWS > 0)\r\nBEGIN\r\n\tDELETE TOP (10000) FROM [MATH].[dbo].[TBL_PRIMES]; \r\n\tSET @VAR_ROWS = @@ROWCOUNT;\r\n\tCHECKPOINT;\r\nEND;\r\nGO\r\n\r\n-- Set to full mode\r\nALTER DATABASE [MATH] SET RECOVERY FULL;\r\nGO\r\n<\/span><\/pre>\n<p>&nbsp;<\/p>\n<p>Both design patterns 2 &#038; 3 do not growth the log file since it is truncated after each batch deletion.  Please see database size from SQL Server Management Studio (SSMS), database properties window.<\/p>\n<p><a href=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/ssms-database-size-after-pattern23.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/ssms-database-size-after-pattern23.jpg\" alt=\"\" title=\"ssms-database-size-after-pattern23\" width=\"1389\" height=\"246\" class=\"alignleft size-full wp-image-3106\" srcset=\"https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/ssms-database-size-after-pattern23.jpg 1389w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/ssms-database-size-after-pattern23-300x53.jpg 300w, https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/ssms-database-size-after-pattern23-1024x181.jpg 1024w\" sizes=\"auto, (max-width: 1389px) 100vw, 1389px\" \/><\/a><\/p>\n<p>&nbsp;<\/P><\/p>\n<p>I purposely skipped talking about database snapshots.  You can use them if you want added protection and quicker recovery from a bad delete statement.  The down side of using them is to have disk space equal to or larger than the data you are deleting.<\/p>\n<p>In summary, be careful when deleting data.  Use the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms188929.aspx\">BEGIN TRAN<\/a> statement for added protection when doing small deletions.  Be cognitive of managing transaction log file growth (<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms179478.aspx\">BACKUP LOG<\/a> or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms188748.aspx\">CHECKPOINT<\/a>) during larger deletions. Use <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms175158.aspx\">DATABASE SNAPSHOTS<\/a> for added protection if have the processing power and space capacity on your server.  <\/p>\n<p>Best wishes on clearing your database of unwanted records.<\/p>\n<p><a href='https:\/\/craftydba.com\/wp-content\/uploads\/2012\/11\/MATH.zip'>MATH DATABASE<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Most of the time, the transaction log is your friend since it can be used for a point in time recovery. However, when deleting large amounts of data from a database, it can be your enemy. I will be reviewing THREE different TSQL patterns to delete data. Today, we will be using the MATH database that contains prime numbers from 2 to 6 million. I will post the actual files on this article so that they can be detached and reattached as needed for each test. We need to remove&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[254,628,311,632,31,634,627,629,12,631,15,633,630,28,29],"class_list":["post-3079","post","type-post","status-publish","format-standard","hentry","category-db-dev","tag-backup-log","tag-begin-tran","tag-checkpoint","tag-commit","tag-database-developer","tag-database-snapshot","tag-delete-batches","tag-delete-top-from","tag-free-code","tag-full","tag-john-f-miner-iii","tag-rollback","tag-simple","tag-sql-server","tag-tsql"],"_links":{"self":[{"href":"https:\/\/craftydba.com\/index.php?rest_route=\/wp\/v2\/posts\/3079","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/craftydba.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/craftydba.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/craftydba.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/craftydba.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3079"}],"version-history":[{"count":0,"href":"https:\/\/craftydba.com\/index.php?rest_route=\/wp\/v2\/posts\/3079\/revisions"}],"wp:attachment":[{"href":"https:\/\/craftydba.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3079"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/craftydba.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3079"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/craftydba.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3079"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}