Skip to content

Commit be486a4

Browse files
Merge pull request #36024 from dimitri-furman/dfurman/cleanup
Fix clean free space, update ghost cleanup
2 parents d7ce5e4 + e69ee77 commit be486a4

File tree

6 files changed

+82
-80
lines changed

6 files changed

+82
-80
lines changed

.openpublishing.redirection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67634,6 +67634,11 @@
6763467634
"redirect_url": "/sql/relational-databases/system-functions/sys-dm-hs-database-log-rate",
6763567635
"redirect_document_id": false
6763667636
},
67637+
{
67638+
"source_path": "docs/relational-databases/ghost-record-cleanup-process-guide.md",
67639+
"redirect_url": "/sql/relational-databases/ghost-row-cleanup-process-guide",
67640+
"redirect_document_id": true
67641+
},
6763767642
{
6763867643
"source_path": "docs/database-engine/install-windows/upgrade-to-a-different-edition-of-sql-server-setup.md",
6763967644
"redirect_url": "/sql/database-engine/install-windows/upgrade-downgrade-sql-server-edition-setup",

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

Lines changed: 0 additions & 55 deletions
This file was deleted.
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
title: "Ghost Cleanup Process Guide"
3+
description: Learn about the ghost cleanup process, a background process that physically removes rows that are marked for deletion from data pages.
4+
author: MashaMSFT
5+
ms.author: mathoma
6+
ms.reviewer: dfurman, randolphwest
7+
ms.date: 12/08/2025
8+
ms.service: sql
9+
ms.subservice: supportability
10+
ms.topic: concept-article
11+
helpviewer_keywords:
12+
- "ghost cleanup"
13+
- "ghost rows"
14+
- "ghost clean up process"
15+
---
16+
17+
# Ghost cleanup process guide
18+
19+
Ghost cleanup is a background process that physically removes the rows that were marked for deletion by DML statements. The following article provides an overview of this process.
20+
21+
## Ghost rows
22+
23+
Rows that are deleted from the leaf level pages of an index aren't physically removed from the page. Instead, the row is marked for future removal, 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 and for snapshot isolation transactions where the database engine must maintain older row versions.
24+
25+
## Ghost cleanup task
26+
27+
Rows that are marked for deletion, or *ghosted*, are cleaned up by the background ghost cleanup process when they're no longer required. Ghost cleanup runs periodically and checks to see if any pages have ghosted rows. If it finds any, it physically removes these rows. There's a single ghost cleanup thread for all databases on a [!INCLUDE [ssde-md](../includes/ssde-md.md)] instance.
28+
29+
When a row is ghosted, the database is marked as having ghosted entries. The ghost cleanup process only scans such databases. The ghost cleanup process also marks the database as having no ghosted rows once all ghosted rows are 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 the database. It retries lock acquisition on the database the next time it runs.
30+
31+
The following query returns an approximate number of ghosted rows in a database.
32+
33+
```sql
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;
39+
```
40+
41+
## Disable ghost cleanup
42+
43+
In high-load systems with many deletes, the ghost cleanup process might reduce performance if it replaces many of the frequently accessed pages in the buffer pool with other pages that have ghosted rows. As a result, the frequently accessed pages must be re-read from disk, generating extra disk I/O and increasing query latency. If this occurs, you can disable ghost cleanup using [trace flag 661](../t-sql/database-console-commands/dbcc-traceon-trace-flags-transact-sql.md#tf661).
44+
45+
Without ghost cleanup, your database can grow unnecessarily large, which can also reduce performance due to extra I/O and memory consumption. Since the ghost cleanup process removes rows that are marked as ghosts, disabling the process leaves these rows 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 increase disk I/O, which can reduce query performance. If ghost cleanup is disabled, the database might run out of space.
46+
47+
> [!WARNING]
48+
> Disabling the ghost cleanup process permanently isn't recommended.
49+
50+
To remove ghost rows when ghost cleanup is disabled, rebuild indexes on tables where rows were deleted. Rebuilding an index creates new pages from existing data, omitting ghosted rows in the process.
51+
52+
## Related content
53+
54+
- [Pages and extents architecture guide](pages-and-extents-architecture-guide.md)

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/08/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 on data 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 before the cleanup of each page, in seconds. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the load on the I/O system at the expense of increasing the duration of the cleanup process.
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_file_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 data space on the page. In environments where the physical security of the data files or the underlying storage is at risk, you can use this stored procedure to ensure that no residual deleted data remains in the data files or in storage.
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/08/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 on data 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 before the cleanup of each page, in seconds. *@cleaning_delay* is **int**, with a default of `0`. This delay helps reduce the load on the I/O system at the expense of increasing the duration of the cleanup process.
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 data space on the page. In environments where the physical security of the data files or the underlying storage is at risk, you can use this stored procedure to ensure that no residual deleted data remains in the data files or in storage.
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)

docs/toc.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4277,11 +4277,11 @@ items:
42774277
items:
42784278
- name: Overview
42794279
href: relational-databases/sql-server-guides.md
4280-
- name: Ghost record cleanup process
4281-
href: relational-databases/ghost-record-cleanup-process-guide.md
4282-
- name: Index architecture & design
4280+
- name: Ghost row cleanup process
4281+
href: relational-databases/ghost-row-cleanup-process-guide.md
4282+
- name: Index architecture and design
42834283
href: relational-databases/sql-server-index-design-guide.md
4284-
- name: Pages & extents architecture
4284+
- name: Pages and extents architecture
42854285
items:
42864286
- name: Overview
42874287
href: relational-databases/pages-and-extents-architecture-guide.md

0 commit comments

Comments
 (0)