{"id":1158,"date":"2007-10-08T16:24:00","date_gmt":"2007-10-08T16:24:00","guid":{"rendered":"\/blogs\/paul\/post\/Inside-the-Storage-Engine-Ghost-cleanup-in-depth.aspx"},"modified":"2017-04-13T09:52:07","modified_gmt":"2017-04-13T16:52:07","slug":"inside-the-storage-engine-ghost-cleanup-in-depth","status":"publish","type":"post","link":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/","title":{"rendered":"Inside the Storage Engine: Ghost cleanup in depth"},"content":{"rendered":"<p><font face=\"Verdana\"><font size=\"2\"><\/p>\n<p>\nOver the years I was in the Storage Engine team I saw a lot of concern on the various forums about the ghost cleanup task. There have been a few bugs with it in previous versions&nbsp; (see these KB articles &#8211; <a href=\"https:\/\/support.microsoft.com\/kb\/932115\">932115<\/a> and <a href=\"https:\/\/support.microsoft.com\/kb\/815594\">815594<\/a>) and there&#39;s very little info available on it. For some reason I didn&#39;t get around to posting about it on my old blog but today I want to go into some depth on it.\n<\/p>\n<p>\nSo what is ghost cleanup? It&#39;s a background process that cleans up ghost records &#8211; usually referred to as the ghost cleanup task. What&#39;s a ghost record? As I described briefly in the <a href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-anatomy-of-a-record\/\">Anatomy of a record post<\/a>&nbsp;last week, a ghost record is one that&#39;s just been deleted <em>in an index on a table<\/em> (well, actually it gets more complicated if snapshot isolation of some form is enabled but for now, a record in an index is a good start).&nbsp;Such a&nbsp;delete operation never physically removes records from pages &#8211; it only marks them as having been deleted, or ghosted. This is a performance optimization that allows delete operations to complete more quickly. It also allows delete operations to rollback more quickly because all that needs to happen is to unmark the records as being deleted\/ghosted, instead of having to reinsert the deleted records. The deleted record will be physically removed (well, its slot will be removed &#8211; the record data isn&#39;t actually overwritten) later by the background ghost cleanup task. The ghost cleanup task will leave a single record on the page to avoid having to deallocate empty data or index pages.\n<\/p>\n<p>\nThe ghost cleanup task can&#39;t physically delete the ghost records until after the delete transaction commits because the deleted records are locked and the locks aren&#39;t released until the transaction commits. As an aside, when ghost records exist on a page, even a NOLOCK or READ UNCOMMITTED scan won&#39;t return them because they are marked as ghost records.\n<\/p>\n<p>\nWhen a record is deleted, apart from it being marked as a ghost record, the page that the record is on is also marked as having ghost records in one of the allocation maps &#8211; the PFS page (post coming soon!) &#8211; and in its page header. Marking a page as having ghost records in a PFS page also changes the database state to indicate that there are some ghost records to cleanup &#8211; somewhere. Nothing tells the ghost cleanup task to clean the specific page that the delete happened on&nbsp;&#8211; yet. That only happens when the next scan operation reads the page and notices that the page has ghost records.\n<\/p>\n<p>\nThe ghost cleanup task doesn&#39;t just start up when it&#39;s told to &#8211; it starts up in the background every 5 seconds and looks for ghost records to cleanup. Remember that it won&#39;t be told to go cleanup a <em>specific<\/em> page by a delete operation &#8211; it&#39;s a subsequent scan that does it, if a scan happens. When the ghost cleanup task starts up it checks to see if its been told to cleanup a page &#8211; if so it goes and does it. If not, it picks the next database that is marked as having some ghost records and looks through the PFS allocation map pages to see if there are any ghost records to cleanup. It will check through or cleanup a limited number of pages each time it wakes up &#8211; I&nbsp;remember the limit is 10 pages &#8211; to ensure it doesn&#39;t swamp the system. So &#8211; the ghost records will eventually be removed &#8211; either by the ghost cleanup task processing a database for ghost records or by it specifically being told to remove them from a page. If it processes a database and doesn&#39;t find any ghost records, it marks the database as not having any ghost records so it will be skipped next time.\n<\/p>\n<p>\nHow can you tell its running? On SQL Server 2005, you can use the following code to see the ghost cleanup task in <font face=\"Courier New\">sys.dm_exec_requests<\/font>:\n<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t<font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\" color=\"#000000\"> myexecrequests <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#008000\">sys.dm_exec_requests<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\" color=\"#000000\"> 1 <\/font><font size=\"2\" color=\"#808080\">= <\/font><font size=\"2\" color=\"#000000\">0<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">SET<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">NOCOUNT<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">ON<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">DECLARE<\/font><\/font><font face=\"Courier New\" size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">INT<\/font><\/font><font size=\"2\" color=\"#0000ff\"> <\/p>\n<p>\n\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#000000\"> 0<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">WHILE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">@a <\/font><font size=\"2\" color=\"#808080\">&lt;<\/font><font size=\"2\" color=\"#000000\"> 1<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\tBEGIN\n\t<\/p>\n<p>\t<\/font><font size=\"2\"><\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\">\n<p>\n\t\t<font face=\"Courier New\"><font size=\"2\" color=\"#0000ff\">INSERT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\"> myexecrequests <\/font><font size=\"2\" color=\"#0000ff\">SELECT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#008000\">sys.dm_exec_requests<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\"> command <\/font><font size=\"2\" color=\"#808080\">LIKE<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;%ghost%&#39;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<font size=\"2\"><\/p>\n<p>\n\t\t<font face=\"Courier New\"><font size=\"2\" color=\"#0000ff\">SELECT<\/font><font size=\"2\"> @a <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff00ff\">COUNT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">(*)<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> myexecrequests<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font>\n\t<\/p><\/blockquote>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">END<\/font><font size=\"2\" color=\"#808080\"><font face=\"Courier New\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> myexecrequests<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p dir=\"ltr\">\n\t<font face=\"Verdana\">And on SQL Server 2000 you need to use <font face=\"Courier New\">sysprocesses<\/font> (well, on SQL Server 2005 this works as well but its fake view derived from the DMVs):<\/font>\n\t<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t\t<font face=\"Verdana\"><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\" color=\"#000000\"> mysysprocesses <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> master<\/font><font size=\"2\" color=\"#808080\">.<\/font><font size=\"2\" color=\"#000000\">dbo<\/font><font size=\"2\" color=\"#808080\">.<\/font><font size=\"2\" color=\"#000000\">sysprocesses <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\" color=\"#000000\"> 1 <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#000000\"> 0<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t<font face=\"Courier New\">SET<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">NOCOUNT<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">ON<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">DECLARE<\/font><\/font><font face=\"Courier New\" size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">INT<\/font><\/font><\/font><font size=\"2\" color=\"#0000ff\"> <\/p>\n<p>\n\t\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#000000\"> 0<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t<font face=\"Courier New\">WHILE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">@a <\/font><font size=\"2\" color=\"#808080\">&lt;<\/font><font size=\"2\" color=\"#000000\"> 1<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font face=\"Courier New\" size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\tBEGIN\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\"><\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\">\n<p>\n\t\t\t<font face=\"Courier New\"><font size=\"2\" color=\"#0000ff\">INSERT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\"> mysysprocesses <\/font><font size=\"2\" color=\"#0000ff\">SELECT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> master<\/font><font size=\"2\" color=\"#808080\">.<\/font><font size=\"2\">dbo<\/font><font size=\"2\" color=\"#808080\">.<\/font><font size=\"2\">sysprocesses <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\"> cmd <\/font><font size=\"2\" color=\"#808080\">LIKE<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;%ghost%&#39;<\/font><\/font>\n\t\t\t<\/p>\n<p>\t\t\t<font size=\"2\"><\/p>\n<p>\n\t\t\t<font face=\"Courier New\"><font size=\"2\" color=\"#0000ff\">SELECT<\/font><font size=\"2\"> @a <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff00ff\">COUNT<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">(*)<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> mysysprocesses<\/font><\/font>\n\t\t\t<\/p>\n<p>\t\t\t<\/font>\n\t\t<\/p><\/blockquote>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t<font face=\"Courier New\">END<\/font><font size=\"2\" color=\"#808080\"><font face=\"Courier New\">;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> mysysprocesses<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font>\n\t<\/p><\/blockquote>\n<p>\t<\/font>\n<\/p><\/blockquote>\n<p><\/font><\/p>\n<p dir=\"ltr\">\n<font face=\"Verdana\">The output from <font face=\"Courier New\">sys.dm_exec_requests<\/font> is (with most unused and uninteresting columns stripped off):<\/font>\n<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\">\n<p dir=\"ltr\">\n\tsession_id request_id&nbsp; start_time&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; status&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;command<br \/>\n\t&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n\t15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2007-10-05 16:34:49.653 background&nbsp;&nbsp;&nbsp;GHOST CLEANUP\n\t<\/p>\n<\/blockquote>\n<p dir=\"ltr\">\n<font face=\"Verdana\">So how can you tell if a record is ghosted? Let&#39;s engineer some and look at it with <font face=\"Courier New\">DBCC PAGE<\/font><\/font><font face=\"Verdana\"> &#8211; I&#39;ve stripped out the uninteresting bits of the output and highlighted the interesting ghost parts:<\/font>\n<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t<font face=\"Verdana\"><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">CREATE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">TABLE<\/font><font size=\"2\" color=\"#000000\"> t1 <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">c1 <\/font><font size=\"2\" color=\"#0000ff\">CHAR<\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">10<\/font><font size=\"2\" color=\"#808080\">))<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">CREATE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">CLUSTERED<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">INDEX<\/font><font size=\"2\" color=\"#000000\"> t1c1 <\/font><font size=\"2\" color=\"#0000ff\">on<\/font><font size=\"2\" color=\"#000000\"> t1 <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">c1<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">BEGIN<\/font><\/font><font face=\"Courier New\" size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">TRAN<\/font><\/font><\/font><font size=\"2\" color=\"#0000ff\"> <\/p>\n<p>\n\t<font face=\"Courier New\">INSERT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\" color=\"#000000\"> t1 <\/font><font size=\"2\" color=\"#0000ff\">VALUES<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;PAUL&#39;<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">INSERT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">INTO<\/font><font size=\"2\" color=\"#000000\"> t1 <\/font><font size=\"2\" color=\"#0000ff\">VALUES<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;KIMBERLY&#39;<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">DELETE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> t1 <font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\"> c1<\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#ff0000\">&#39;KIMBERLY&#39;<\/font><\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">DBCC<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> IND <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;ghostrecordtest&#39;<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;t1&#39;<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\" color=\"#000000\"> 1<\/font><font size=\"2\" color=\"#808080\">);<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">DBCC<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> TRACEON <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">3604<\/font><font size=\"2\" color=\"#808080\">);<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">DBCC<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> PAGE <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;ghostrecordtest&#39;<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\" color=\"#000000\"> 1<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\" color=\"#000000\"> 143<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\" color=\"#000000\"> 3<\/font><font size=\"2\" color=\"#808080\">);<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\n\t&lt;snip&gt;\n\t<\/p>\n<p>\n\tm_freeData = 130&nbsp;&nbsp;&nbsp;&nbsp;m_reservedCnt = 0&nbsp;&nbsp;&nbsp;m_lsn = (20:88:20)<br \/>\n\tm_xactReserved = 0&nbsp;&nbsp;m_xdesId = (0:518)&nbsp;&nbsp;<strong>m_ghostRecCnt = 1<\/strong><br \/>\n\tm_tornBits = 0\n\t<\/p>\n<p>\n\t&lt;snip&gt;\n\t<\/p>\n<p>\n\tSlot 0 Offset 0x71 Length 17\n\t<\/p>\n<p>\n\tRecord Type = <strong>GHOST_DATA_RECORD<\/strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Record Attributes =&nbsp; NULL_BITMAP<br \/>\n\tMemory Dump @0x6256C071\n\t<\/p>\n<p>\n\t00000000:&nbsp;&nbsp; 1c000e00 4b494d42 45524c59 20200200 &dagger;&#8230;.KIMBERLY&nbsp; ..<br \/>\n\t00000010:&nbsp;&nbsp; fc&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;.<br \/>\n\tUNIQUIFIER = [NULL]\n\t<\/p>\n<p>\n\tSlot 0 Column 1 Offset 0x4 Length 10\n\t<\/p>\n<p>\n\tc1 = KIMBERLY\n\t<\/p>\n<p>\n\tSlot 1 Offset 0x60 Length 17\n\t<\/p>\n<p>\n\tRecord Type = PRIMARY_RECORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Record Attributes =&nbsp; NULL_BITMAP<br \/>\n\tMemory Dump @0x6256C060\n\t<\/p>\n<p>\n\t00000000:&nbsp;&nbsp; 10000e00 5041554c 20202020 20200200 &dagger;&#8230;.PAUL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ..<br \/>\n\t00000010:&nbsp;&nbsp; fc&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;.<br \/>\n\tUNIQUIFIER = [NULL]\n\t<\/p>\n<p>\n\tSlot 1 Column 1 Offset 0x4 Length 10\n\t<\/p>\n<p>\n\t<font face=\"Verdana\"><font face=\"Courier New\">c1 = PAUL<\/font><\/font>\n\t<\/p>\n<p>\t<\/font>\n<\/p><\/blockquote>\n<p><\/font><font face=\"Verdana\"><font size=\"2\"><\/p>\n<p>\nLet&#39;s see what goes on the transaction log during this process (remember this is undocumented and unsupported &#8211; do it on a test database) &#8211; I&#39;ve stripped off a bunch of the columns in the output:\n<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t<font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">DECLARE<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#0000ff\">CHAR<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#000000\">20<\/font><font size=\"2\" color=\"#808080\">)<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> @a <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#000000\"> [Transaction ID] <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> fn_dblog <\/font><font size=\"2\" color=\"#808080\">(null,<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">null)<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\" color=\"#000000\"> [Transaction Name]<\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\" color=\"#ff0000\">&#39;PaulsTran&#39;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\" color=\"#0000ff\"><font face=\"Courier New\">SELECT<\/font><\/font><font face=\"Courier New\"><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\" color=\"#000000\"> fn_dblog <\/font><font size=\"2\" color=\"#808080\">(null,<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#808080\">null)<\/font><font size=\"2\" color=\"#000000\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\" color=\"#000000\"> [Transaction ID] <\/font><font size=\"2\" color=\"#808080\">=<\/font><font size=\"2\"><font color=\"#000000\"> @a<font size=\"2\" color=\"#808080\">;<\/font><\/font><\/font><\/font><font face=\"Courier New\"><font size=\"2\"><font color=\"#000000\"><font size=\"2\" color=\"#808080\"><\/font><font size=\"2\"> <\/p>\n<p>\n\tGO\n\t<\/p>\n<p>\t<\/font><\/font><\/font><\/font><\/p>\n<p>\n\t<font face=\"Courier New\"><font size=\"2\"><font color=\"#000000\">Current LSN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Transaction ID<br \/>\n\t&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n\t00000014:00000054:0011&nbsp;&nbsp; LOP_BEGIN_XACT&nbsp;&nbsp;&nbsp;&nbsp;LCX_NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0000:00000206<br \/>\n\t00000014:0000005a:0012&nbsp;&nbsp; LOP_INSERT_ROWS&nbsp;&nbsp;&nbsp;LCX_CLUSTERED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0000:00000206<br \/>\n\t00000014:0000005a:0013&nbsp;&nbsp; LOP_INSERT_ROWS&nbsp;&nbsp;&nbsp;LCX_CLUSTERED&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0000:00000206<br \/>\n\t00000014:0000005a:0014&nbsp;&nbsp; LOP_DELETE_ROWS&nbsp;&nbsp;&nbsp;LCX_MARK_AS_GHOST&nbsp;&nbsp;&nbsp;0000:00000206<br \/>\n\t00000014:0000005a:0016&nbsp;&nbsp; LOP_DELETE_ROWS&nbsp;&nbsp;&nbsp;LCX_MARK_AS_GHOST&nbsp;&nbsp;&nbsp;0000:00000206<\/font><\/font><\/font>\n\t<\/p>\n<\/blockquote>\n<p><\/font><\/p>\n<p dir=\"ltr\">\n<font face=\"Courier New\"><font size=\"2\"><font face=\"Verdana\" color=\"#000000\">So there are the two inserts followed by the two deletes &#8211; with the rows being marked as ghost records. But where&#39;s the update to the PFS page? Well, changing the ghost bit in a&nbsp;PFS&nbsp;page&nbsp;is not done as part of a transaction. We&#39;ll need to look for it another way (apart from just dumping everything in the transaction log and searching manually):<\/font><\/font><\/font>\n<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t<font face=\"Courier New\"><font size=\"2\"><font face=\"Verdana\" color=\"#000000\"><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t<font face=\"Courier New\">SELECT<\/font><font face=\"Courier New\"><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">Description<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> fn_dblog <\/font><font size=\"2\" color=\"#808080\">(null,<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">null)<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\"> Context <\/font><font size=\"2\" color=\"#808080\">like<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;%PFS%&#39;<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">AND<\/font><font size=\"2\"> AllocUnitName <\/font><font size=\"2\" color=\"#808080\">like<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;%t1%&#39;<\/font><font size=\"2\" color=\"#808080\">;<\/font><\/font>\n\t<\/p>\n<p>\t<\/font><font size=\"2\"><\/p>\n<p>\n\t<font face=\"Courier New\">GO<\/font>\n\t<\/p>\n<p>\n\t<font face=\"Courier New\">Description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Current LSN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;&nbsp;&nbsp;Transaction ID<br \/>\n\t&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;- &#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n\tAllocated 0001:0000008f&nbsp;&nbsp; 00000014:00000054:0014&nbsp;&nbsp; LOP_MODIFY_ROW&nbsp;&nbsp;&nbsp;LCX_PFS&nbsp;&nbsp;&nbsp;0000:00000208<br \/>\n\t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000014:0000005a:0015&nbsp;&nbsp; LOP_SET_BITS&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCX_PFS&nbsp;&nbsp;&nbsp;0000:00000000<\/font>\n\t<\/p>\n<p dir=\"ltr\">\n\tThe first one is just allocating a page but the second one is the one we&#39;re looking for &#8211; it&#39;s changed the bit for the page to say it has ghost records on. Let&#39;s commit the transaction and see what happens, filtering out all the previous transaction log:\n\t<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t\t<font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\tSELECT<font size=\"2\"> <\/font><font size=\"2\" color=\"#ff00ff\">MAX<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\">[Current LSN]<\/font><font size=\"2\" color=\"#808080\">)<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> fn_dblog <\/font><font size=\"2\" color=\"#808080\">(null,<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">null);<\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#008000\"><\/p>\n<p>\n\t\t&#8212; 00000014:0000005e:0001\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\tCOMMIT<font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">TRAN<\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\tSELECT<font size=\"2\"> <font size=\"2\">[Page ID]<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> <\/font><\/font><font size=\"2\" color=\"#808080\">*<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">FROM<\/font><font size=\"2\"> fn_dblog <\/font><font size=\"2\" color=\"#808080\">(null,<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#808080\">null)<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#0000ff\">WHERE<\/font><font size=\"2\"> [Current LSN] <\/font><font size=\"2\" color=\"#808080\">&gt;<\/font><font size=\"2\"> <\/font><font size=\"2\" color=\"#ff0000\">&#39;00000014:0000005e:0001&#39;<\/font><font size=\"2\" color=\"#808080\">;<\/font>\n\t\t<\/p>\n<p>\t\t<\/font><font size=\"2\"><\/p>\n<p>\n\t\tGO\n\t\t<\/p>\n<p>\n\t\t<font face=\"Courier New\">Page ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Current LSN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Operation&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Transaction ID<br \/>\n\t\t&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8212; &#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n\t\tNULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 00000014:0000005f:0001&nbsp;&nbsp; LOP_COMMIT_XACT&nbsp;&nbsp;&nbsp;&nbsp;LCX_NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0000:00000206<br \/>\n\t\t0001:0000008f&nbsp;&nbsp; 00000014:00000060:0001&nbsp;&nbsp; LOP_EXPUNGE_ROWS&nbsp;&nbsp;&nbsp;LCX_CLUSTERED&nbsp;&nbsp;&nbsp;0000:00000000<\/font>\n\t\t<\/p>\n<p dir=\"ltr\">\n\t\tWe see that almost as soon as the transaction has commited, the ghost cleanup task goes in and process the page. Let&#39;s check a page dump to make sure the record is gone, and show that the contents of the record are still on the page (again, with non-relevant bits snipped out):\n\t\t<\/p>\n<blockquote dir=\"ltr\" style=\"margin-right: 0px\"><p>\n\t\t\t<font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t\t<font face=\"Courier New\">DBCC<\/font><font face=\"Courier New\"><font size=\"2\"> PAGE <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;ghostrecordtest&#39;<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 1<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 143<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 3<\/font><font size=\"2\" color=\"#808080\">);<\/font><\/font>\n\t\t\t<\/p>\n<p>\t\t\t<\/font><font face=\"Courier New\" size=\"2\"><\/p>\n<p>\n\t\t\tGO\n\t\t\t<\/p>\n<p>\n\t\t\t&lt;snip&gt;\n\t\t\t<\/p>\n<p>\n\t\t\tm_freeData = 130&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_reservedCnt = 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_lsn = (20:94:1)<br \/>\n\t\t\tm_xactReserved = 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_xdesId = (0:518)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>m_ghostRecCnt = 0<\/strong><br \/>\n\t\t\tm_tornBits = 0\n\t\t\t<\/p>\n<p>\n\t\t\t&lt;snip&gt;\n\t\t\t<\/p>\n<p>\n\t\t\tRecord Type = PRIMARY_RECORD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Record Attributes =&nbsp; NULL_BITMAP<br \/>\n\t\t\tMemory Dump @0x6212C060\n\t\t\t<\/p>\n<p>\n\t\t\t00000000:&nbsp;&nbsp; 10000e00 5041554c 20202020 20200200 &dagger;&#8230;.PAUL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ..<br \/>\n\t\t\t00000010:&nbsp;&nbsp; fc&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;&dagger;.<br \/>\n\t\t\tUNIQUIFIER = [NULL]\n\t\t\t<\/p>\n<p>\n\t\t\tSlot 0 Column 1 Offset 0x4 Length 10\n\t\t\t<\/p>\n<p>\n\t\t\tc1 = PAUL\n\t\t\t<\/p>\n<p>\t\t\t<font size=\"2\" color=\"#0000ff\"><\/p>\n<p>\n\t\t\tDBCC<font size=\"2\"> PAGE <\/font><font size=\"2\" color=\"#808080\">(<\/font><font size=\"2\" color=\"#ff0000\">&#39;ghostrecordtest&#39;<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 1<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 143<\/font><font size=\"2\" color=\"#808080\">,<\/font><font size=\"2\"> 2<\/font><font size=\"2\" color=\"#808080\">);<\/font>\n\t\t\t<\/p>\n<p>\t\t\t<\/font><font size=\"2\"><\/p>\n<p>\n\t\t\tGO\n\t\t\t<\/p>\n<p>\t\t\t<\/font><\/p>\n<p>\n\t\t\t&lt;snip&gt;\n\t\t\t<\/p>\n<p>\n\t\t\t6212C040:&nbsp;&nbsp; 01000000 00000000 00000000 00000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t\t\t6212C050:&nbsp;&nbsp; 00000000 00000000 00000000 00000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t\t\t6212C060:&nbsp;&nbsp; 10000e00 5041554c 20202020 20200200 &dagger;&#8230;.PAUL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ..<br \/>\n\t\t\t6212C070:&nbsp;&nbsp; fc1c000e 004b494d 4245524c 59202002 &dagger;&#8230;..<strong>KIMBERLY<\/strong>&nbsp; .<br \/>\n\t\t\t6212C080:&nbsp;&nbsp; 00fc0000 00000000 00000000 01000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.<br \/>\n\t\t\t6212C090:&nbsp;&nbsp; 00000000 13000000 01000000 00000000 &dagger;&#8230;&#8230;&#8230;&#8230;&#8230;.\n\t\t\t<\/p>\n<p>\n\t\t\t&lt;snip&gt;\n\t\t\t<\/p>\n<p>\t\t\t<\/font>\n\t\t<\/p><\/blockquote>\n<p dir=\"ltr\">\n\t\tSo even though the record no longer exists, all that happened was that the slot was removed from the slot array at the end of the page &#8211; the record contents will remain on the page until the space is reused.\n\t\t<\/p>\n<p dir=\"ltr\">\n\t\tIn the next post I&#39;ll go into details of the PFS and other allocation maps. Btw &#8211; please let me know if this stuff is interesting &#8211; I&#39;d like to know where to spend blogging time. Thanks!\n\t\t<\/p>\n<p>\t\t<\/font>\n\t<\/p><\/blockquote>\n<p>\t<\/font><\/font><\/font><\/font>\n<\/p><\/blockquote>\n<p><\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over the years I was in the Storage Engine team I saw a lot of concern on the various forums about the ghost cleanup task. There have been a few bugs with it in previous versions&nbsp; (see these KB articles &#8211; 932115 and 815594) and there&#39;s very little info available on it. For some reason [&hellip;]<\/p>\n","protected":false},"author":5,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[38,48,62,98,100],"tags":[],"class_list":["post-1158","post","type-post","status-publish","format-standard","hentry","category-example-scripts","category-inside-the-storage-engine","category-on-disk-structures","category-transaction-log","category-undocumented-commands"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal\" \/>\n<meta property=\"og:description\" content=\"Over the years I was in the Storage Engine team I saw a lot of concern on the various forums about the ghost cleanup task. There have been a few bugs with it in previous versions&nbsp; (see these KB articles &#8211; 932115 and 815594) and there&#039;s very little info available on it. For some reason [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/\" \/>\n<meta property=\"og:site_name\" content=\"Paul S. Randal\" \/>\n<meta property=\"article:published_time\" content=\"2007-10-08T16:24:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-04-13T16:52:07+00:00\" \/>\n<meta name=\"author\" content=\"Paul Randal\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Paul Randal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/\",\"name\":\"Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal\",\"isPartOf\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\"},\"datePublished\":\"2007-10-08T16:24:00+00:00\",\"dateModified\":\"2017-04-13T16:52:07+00:00\",\"author\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Inside the Storage Engine: Ghost cleanup in depth\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#website\",\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/\",\"name\":\"Paul S. Randal\",\"description\":\"In Recovery...\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce\",\"name\":\"Paul Randal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g\",\"caption\":\"Paul Randal\"},\"sameAs\":[\"http:\/\/3.209.169.194\/blogs\/paul\"],\"url\":\"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/","og_locale":"en_US","og_type":"article","og_title":"Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal","og_description":"Over the years I was in the Storage Engine team I saw a lot of concern on the various forums about the ghost cleanup task. There have been a few bugs with it in previous versions&nbsp; (see these KB articles &#8211; 932115 and 815594) and there&#39;s very little info available on it. For some reason [&hellip;]","og_url":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/","og_site_name":"Paul S. Randal","article_published_time":"2007-10-08T16:24:00+00:00","article_modified_time":"2017-04-13T16:52:07+00:00","author":"Paul Randal","twitter_misc":{"Written by":"Paul Randal","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/","name":"Inside the Storage Engine: Ghost cleanup in depth - Paul S. Randal","isPartOf":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website"},"datePublished":"2007-10-08T16:24:00+00:00","dateModified":"2017-04-13T16:52:07+00:00","author":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce"},"breadcrumb":{"@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/inside-the-storage-engine-ghost-cleanup-in-depth\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.sqlskills.com\/blogs\/paul\/"},{"@type":"ListItem","position":2,"name":"Inside the Storage Engine: Ghost cleanup in depth"}]},{"@type":"WebSite","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#website","url":"https:\/\/www.sqlskills.com\/blogs\/paul\/","name":"Paul S. Randal","description":"In Recovery...","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.sqlskills.com\/blogs\/paul\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/ffcec826c18782e1e0adf173826a7fce","name":"Paul Randal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.sqlskills.com\/blogs\/paul\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0b6a266bba2f088f2551ef529293001bd73bf026bc1908b9866728c062beeeb6?s=96&d=mm&r=g","caption":"Paul Randal"},"sameAs":["http:\/\/3.209.169.194\/blogs\/paul"],"url":"https:\/\/www.sqlskills.com\/blogs\/paul\/author\/paul\/"}]}},"_links":{"self":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/1158","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/comments?post=1158"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/posts\/1158\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/media?parent=1158"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/categories?post=1158"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlskills.com\/blogs\/paul\/wp-json\/wp\/v2\/tags?post=1158"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}