Skip to content

Commit 2dcb850

Browse files
Fix clean free space, update ghost cleanup
1 parent 357f5f2 commit 2dcb850

File tree

3 files changed

+39
-40
lines changed

3 files changed

+39
-40
lines changed

docs/relational-databases/ghost-record-cleanup-process-guide.md

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ title: "Ghost cleanup process guide"
33
description: Learn about the ghost cleanup process, a background process that deletes records off of pages that have been marked for deletion in SQL Server.
44
author: MashaMSFT
55
ms.author: mathoma
6-
ms.date: "05/02/2018"
6+
ms.reviewer: dfurman
7+
ms.date: 12/07/2025
78
ms.service: sql
89
ms.subservice: supportability
910
ms.topic: conceptual
@@ -12,44 +13,44 @@ helpviewer_keywords:
1213
- "ghost records"
1314
- "ghost clean up process"
1415
---
16+
1517
# Ghost cleanup process guide
1618

17-
The ghost cleanup process is a single-threaded background process that deletes records off of pages that have been marked for deletion. The following article provides an overview of this process.
19+
The ghost cleanup process is a single-threaded background process that deletes records marked for deletion in data pages. The following article provides an overview of this process.
1820

1921
## Ghost records
2022

21-
Records that are deleted from a leaf level of an index page aren't physically removed from the page - instead, the record is marked as 'to be deleted', or *ghosted*. This means that the row stays on the page but a bit is changed in the row header to indicate that the row is really a ghost. This is to optimize performance during a delete operation. Ghosts are necessary for row-level locking, but are also necessary for snapshot isolation where we need to maintain the older versions of rows.
23+
Records that are deleted from the leaf level of an index page aren't physically removed from the page. Instead, the record is marked as 'to be deleted', or *ghosted*. This means that the row stays on the page but a bit is changed in the row header to indicate that the row is a ghost. This is to optimize performance during a delete operation. Ghosts are necessary for row-level locking, but are also necessary for snapshot isolation where the database engine must maintain older row versions.
2224

2325
## Ghost record cleanup task
2426

25-
Records that are marked for deletion, or *ghosted*, are cleaned up by the background ghost cleanup process. This background process runs sometime after the delete transaction is committed, and physically removes ghosted records from pages. The ghost cleanup process runs automatically on an interval (every 5 seconds for SQL Server 2012+, every 10 seconds for SQL Server 2008/2008R2) and checks to see if any pages have been marked with ghost records. If it finds any, then it goes and deletes the records that are marked for deletion, or *ghosted*, touching at most 10 pages with each execution.
27+
Records that are marked for deletion, or *ghosted*, are cleaned up by the background ghost cleanup process when they are no longer required. This background process runs after the delete transaction is committed and all row versions are no longer required, and physically removes ghosted records from pages. The ghost cleanup process runs periodically and checks to see if any pages have ghost records. If it finds any, it physically removes the records that are marked for deletion, or *ghosted*, touching at most 10 pages with each execution.
2628

27-
When a record is ghosted, the database is marked as having ghosted entries, and the ghost cleanup process will only scan those databases. The ghost cleanup process will also mark the database as 'having no ghosted records' once all ghosted records have been deleted, and it will skip this database the next time it runs. The process will also skip any databases it is unable to take a shared lock on, and will try again the next time it runs.
29+
When a record is ghosted, the database is marked as having ghosted entries, and the ghost cleanup process only scans such databases. The ghost cleanup process also marks the database as having no ghosted records once all ghosted records have been removed, and skips this database the next time it runs. The process also skips any database if it can't acquire a shared lock on on the database. It retries acquiring the lock the next time it runs.
2830

29-
The below query can identify how many ghosted records exist in a single database.
31+
The below query returns an approximate number of ghosted records in a database.
3032

3133
```sql
32-
SELECT sum(ghost_record_count) total_ghost_records, db_name(database_id)
33-
FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, 'SAMPLED')
34-
group by database_id
35-
order by total_ghost_records desc
34+
SELECT SUM(ghost_record_count) AS total_ghost_records,
35+
DB_NAME(database_id) AS database_name
36+
FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, 'SAMPLED')
37+
GROUP BY database_id
38+
ORDER BY total_ghost_records DESC;
3639
```
3740

3841
## Disable the ghost cleanup
3942

40-
On high-load systems with many deletes, the ghost cleanup process can cause a performance issue from keeping pages in the buffer pool and generating IO. As such, it is possible to disable this process with the use of [trace flag 661](../t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql.md). However, there are performance implications from disabling the process.
41-
42-
Disabling the ghost cleanup process can cause your database to grow unnecessarily large and can lead to performance issues. Since the ghost cleanup process removes records that are marked as ghosts, disabling the process will leave these records on the page, preventing SQL Server from reusing this space. This forces SQL Server to add data to new pages instead, leading to bloated database files, and can also cause [page splits](indexes/specify-fill-factor-for-an-index.md). Page splits lead to performance issues when creating execution plans, and when doing scan operations.
43+
In rare cases in high-load systems with many deletes, the ghost cleanup process can cause a performance issue because it can replace the frequently accessed pages in the buffer pool with pages that have ghosted records, and generate extra IO load. If this occurs, you can temporarily disable this process with the use of [trace flag 661](../t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql.md#tf661).
4344

44-
Once the ghost cleanup process is disabled, some action needs to be taken to remove the ghosted records. One option is to execute an index rebuild, which will move data around on pages. Another option is to manually run [sp_clean_db_free_space](system-stored-procedures/sp-clean-db-free-space-transact-sql.md) (to clean all database data files) or [sp_clean_db_file_free_space](system-stored-procedures/sp-clean-db-file-free-space-transact-sql.md) (to clean a single database datafile), which will delete ghosted records.
45+
Disabling ghost cleanup permanently is not recommended. Without ghost cleanup, your database can grow unnecessarily large, which can lead to performance issues. Since the ghost cleanup process removes records that are marked as ghosts, disabling the process leaves these records on the page, preventing the database engine from reusing this space. This forces the database engine to add data to new pages instead, leading to bloated database files, and can also cause [page splits](indexes/specify-fill-factor-for-an-index.md). Page splits lead increase disk IO which can reduce query performance.
4546

46-
>[!warning]
47-
> Disabling the ghost cleanup process is not generally recommended. Doing so should be tested thoroughly in a controlled environment before being implemented permanently in a production environment.
47+
Once the ghost cleanup process is disabled, some action needs to be taken to remove the ghosted records. For example, you can rebuild indexes, which creates new pages from existing data, omitting ghosted records.
4848

49+
> [!WARNING]
50+
> Disabling the ghost cleanup process is not recommended.
4951
50-
## Related content
52+
## Related content
5153

52-
- [Remove ghost records from a single database file](system-stored-procedures/sp-clean-db-file-free-space-transact-sql.md)
53-
- [Remove ghost records from all database data files](system-stored-procedures/sp-clean-db-free-space-transact-sql.md)
54+
- [Pages and extents architecture guide](pages-and-extents-architecture-guide.md)
5455

5556

docs/relational-databases/system-stored-procedures/sp-clean-db-file-free-space-transact-sql.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ title: "sp_clean_db_file_free_space (Transact-SQL)"
33
description: Removes residual information left on database pages in a database file, because of data modification routines in SQL Server.
44
author: markingmyname
55
ms.author: maghan
6-
ms.reviewer: randolphwest
7-
ms.date: 06/23/2025
6+
ms.reviewer: randolphwest, dfurman
7+
ms.date: 12/06/2025
88
ms.service: sql
99
ms.subservice: system-objects
1010
ms.topic: "reference"
@@ -17,11 +17,12 @@ helpviewer_keywords:
1717
dev_langs:
1818
- "TSQL"
1919
---
20+
2021
# sp_clean_db_file_free_space (Transact-SQL)
2122

22-
[!INCLUDE [SQL Server](../../includes/applies-to-version/sqlserver.md)]
23+
[!INCLUDE [sql-asdbmi](../../includes/applies-to-version/sql-asdbmi.md)]
2324

24-
Removes residual information left on database pages because of data modification routines in [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)]. `sp_clean_db_file_free_space` cleans all pages in only one file of a database.
25+
Removes residual information left on database pages. `sp_clean_db_file_free_space` cleans all pages in only one file of a database.
2526

2627
:::image type="icon" source="../../includes/media/topic-link-icon.svg" border="false"::: [Transact-SQL syntax conventions](../../t-sql/language-elements/transact-sql-syntax-conventions-transact-sql.md)
2728

@@ -47,21 +48,21 @@ The data file ID to clean. *@fileid* is **int**, with no default.
4748

4849
#### [ @cleaning_delay = ] *cleaning_delay*
4950

50-
Specifies an interval to delay between the cleaning of pages. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the effect on the I/O system.
51+
Specifies an interval to delay between the cleaning of pages. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the load on the I/O system.
5152

5253
## Return code values
5354

5455
`0` (success) or `1` (failure).
5556

5657
## Remarks
5758

58-
Deletes operations from a table or update operations that cause a row to move can immediately free up space on a page by removing references to the row. However, under certain circumstances, the row can physically remain on the data page as a ghost record. A background process periodically removes ghost records. This residual data isn't returned by the [!INCLUDE [ssDE](../../includes/ssde-md.md)] in response to queries. However, in environments in which the physical security of the data or backup files is at risk, you can use `sp_clean_db_file_free_space` to clean these ghost records. To perform this operation for all database files at once, use [sp_clean_db_free_space](sp-clean-db-free-space-transact-sql.md).
59+
The `sp_clean_db_free_space` system stored procedure moves all rows on a page, including the ghosted records if any, to the beginning of the page and then zero-initializes the remainder of the space on the page. In environments where the physical security of the data files is at risk, you can use this stored procedure to ensure that no residual deleted data remain in the data files.
5960

60-
The length of time required to run `sp_clean_db_file_free_space` depends on the size of the file, the available free space, and the capacity of the disk. Because running `sp_clean_db_file_free_space` can significantly affect I/O activity, we recommend that you run this procedure outside usual operation hours.
61+
The time required to run `sp_clean_db_file_free_space` depends on the size of the data file, the number of used pages in the file, and the I/O capabilities of the disk. Because running `sp_clean_db_file_free_space` can significantly increase I/O activity, we recommend that you run this procedure outside the usual operation hours.
6162

6263
Before you run `sp_clean_db_file_free_space`, we recommend that you create a full database backup.
6364

64-
The related [sp_clean_db_free_space](sp-clean-db-free-space-transact-sql.md) stored procedure cleans all files in the database.
65+
To perform this operation for all data files in a database, use [sp_clean_db_free_space](sp-clean-db-free-space-transact-sql.md).
6566

6667
## Permissions
6768

@@ -82,6 +83,4 @@ EXECUTE sp_clean_db_file_free_space
8283

8384
## Related content
8485

85-
- [Database Engine stored procedures (Transact-SQL)](database-engine-stored-procedures-transact-sql.md)
86-
- [Ghost cleanup process guide](../ghost-record-cleanup-process-guide.md)
8786
- [sp_clean_db_free_space (Transact-SQL)](sp-clean-db-free-space-transact-sql.md)

docs/relational-databases/system-stored-procedures/sp-clean-db-free-space-transact-sql.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ title: "sp_clean_db_free_space (Transact-SQL)"
33
description: Removes residual information left on database pages because of data modification routines in SQL Server.
44
author: markingmyname
55
ms.author: maghan
6-
ms.reviewer: randolphwest
7-
ms.date: 06/23/2025
6+
ms.reviewer: randolphwest, dfurman
7+
ms.date: 12/06/2025
88
ms.service: sql
99
ms.subservice: system-objects
1010
ms.topic: "reference"
@@ -17,11 +17,12 @@ helpviewer_keywords:
1717
dev_langs:
1818
- "TSQL"
1919
---
20+
2021
# sp_clean_db_free_space (Transact-SQL)
2122

22-
[!INCLUDE [SQL Server](../../includes/applies-to-version/sqlserver.md)]
23+
[!INCLUDE [sql-asdbmi](../../includes/applies-to-version/sql-asdbmi.md)]
2324

24-
Removes residual information left on database pages because of data modification routines in [!INCLUDE [ssNoVersion](../../includes/ssnoversion-md.md)]. `sp_clean_db_free_space` cleans all pages in all files of the database.
25+
Removes residual information left on database pages. `sp_clean_db_free_space` cleans all pages in all data files of the database.
2526

2627
:::image type="icon" source="../../includes/media/topic-link-icon.svg" border="false"::: [Transact-SQL syntax conventions](../../t-sql/language-elements/transact-sql-syntax-conventions-transact-sql.md)
2728

@@ -42,29 +43,29 @@ The name of the database to clean. *@dbname* is **sysname**, with no default.
4243

4344
#### [ @cleaning_delay = ] *cleaning_delay*
4445

45-
Specifies an interval to delay between the cleaning of pages. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the effect on the I/O system.
46+
Specifies an interval to delay between the cleaning of pages. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the load on the I/O system.
4647

4748
## Return code values
4849

4950
`0` (success) or `1` (failure).
5051

5152
## Remarks
5253

53-
Delete operations from a table or update operations that cause a row to move can immediately free up space on a page by removing references to the row. However, under certain circumstances, the row can physically remain on the data page as a ghost record. A background process periodically removes ghost records. This residual data isn't returned by the [!INCLUDE [ssDE](../../includes/ssde-md.md)] in response to queries. However, in environments in which the physical security of the data or backup files is at risk, you can use `sp_clean_db_free_space` to clean these ghost records. To perform this operation per database file, use [sp_clean_db_file_free_space](sp-clean-db-file-free-space-transact-sql.md).
54+
The `sp_clean_db_free_space` system stored procedure moves all rows on a page, including the ghosted records if any, to the beginning of the page and then zero-initializes the remainder of the space on the page. In environments where the physical security of the data files is at risk, you can use this stored procedure to ensure that no residual deleted data remain in the data files.
5455

55-
The length of time required to run `sp_clean_db_free_space` depends on the size of the file, the available free space, and the capacity of the disk. Because running `sp_clean_db_free_space` can significantly affect I/O activity, we recommend that you run this procedure outside usual operation hours.
56+
The time required to run `sp_clean_db_free_space` depends on the size of the data files, the number of used pages in the files, and the I/O capabilities of the disk. Because running `sp_clean_db_free_space` can significantly increase I/O activity, we recommend that you run this procedure outside the usual operation hours.
5657

5758
Before you run `sp_clean_db_free_space`, we recommend that you create a full database backup.
5859

59-
The related [sp_clean_db_file_free_space](sp-clean-db-file-free-space-transact-sql.md) stored procedure can clean a single file.
60+
To perform this operation per database file, use [sp_clean_db_file_free_space](sp-clean-db-file-free-space-transact-sql.md).
6061

6162
## Permissions
6263

6364
Requires membership in the `db_owner` database role.
6465

6566
## Examples
6667

67-
The following example cleans all residual information from the [!INCLUDE [sssampledbobject-md](../../includes/sssampledbobject-md.md)] database.
68+
The following example cleans all residual data from the [!INCLUDE [sssampledbobject-md](../../includes/sssampledbobject-md.md)] database.
6869

6970
```sql
7071
USE master;
@@ -75,6 +76,4 @@ EXECUTE sp_clean_db_free_space @dbname = N'AdventureWorks2022';
7576

7677
## Related content
7778

78-
- [Database Engine stored procedures (Transact-SQL)](database-engine-stored-procedures-transact-sql.md)
79-
- [Ghost cleanup process guide](../ghost-record-cleanup-process-guide.md)
8079
- [sp_clean_db_file_free_space (Transact-SQL)](sp-clean-db-file-free-space-transact-sql.md)

0 commit comments

Comments
 (0)