You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
26
+
27
+
## Ghost records
28
+
29
+
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.
30
+
31
+
## Ghost record cleanup task
32
+
33
+
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.
34
+
35
+
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.
36
+
37
+
The below query can identify how many ghosted records exist in a single database.
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. More information about this can be found in [Tuning options for SQL Server when running high performance workloads](https://support.microsoft.com/en-us/help/920093/tuning-options-for-sql-server-when-running-in-high-performance-workloa). However, there are performance implications from disabling the process.
49
+
50
+
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.
51
+
52
+
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.
53
+
54
+
>[!warning]
55
+
> 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.
56
+
57
+
58
+
## Next steps
59
+
[Disabling the ghost clean up process](https://support.microsoft.com/en-us/help/920093/tuning-options-for-sql-server-when-running-in-high-performance-workloa)
60
+
<br>[Remove ghost records from a single database file](/system-stored-procedures/sp-clean-db-file-free-space-transact-sql.md)
61
+
<br>[Remove ghost records from all database data files](/system-stored-procedures/sp-clean-db-free-space-transact-sql.md)
Copy file name to clipboardExpand all lines: docs/t-sql/functions/string-split-transact-sql.md
+33-37Lines changed: 33 additions & 37 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,10 +29,8 @@ manager: craigg
29
29
Splits the character expression using specified separator.
30
30
31
31
> [!NOTE]
32
-
> The **STRING_SPLIT** function is available only under compatibility level 130. If your database compatibility level is lower than 130, SQL Server will not be able to find and execute **STRING_SPLIT** function. You can change a compatibility level of database using the following command:
33
-
> ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130
34
-
>
35
-
> Note that compatibility level 120 might be default even in new Azure SQL Databases.
32
+
> The **STRING_SPLIT** function is available only under compatibility level 130 and above. If your database compatibility level is lower than 130, [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] will not be able to find and execute **STRING_SPLIT** function. To change the compatibility level of a database, refer to [View or Change the Compatibility Level of a Database](../../relational-databases/databases/view-or-change-the-compatibility-level-of-a-database.md).
33
+
> Note that compatibility level 120 might be default even in new [!INCLUDE[ssSDSfull](../../includes/sssdsfull-md.md)].
36
34
37
35
[Transact-SQL Syntax Conventions](../../t-sql/language-elements/transact-sql-syntax-conventions-transact-sql.md)
Is an [expression](../../t-sql/language-elements/expressions-transact-sql.md) of any character type (i.e. **nvarchar**, **varchar**, **nchar** or **char**).
45
+
Is an [expression](../../t-sql/language-elements/expressions-transact-sql.md) of any character type (for example, **nvarchar**, **varchar**, **nchar**, or **char**).
48
46
49
47
*separator*
50
-
Is a single character [expression](../../t-sql/language-elements/expressions-transact-sql.md) of any character type (e.g. **nvarchar(1)**, **varchar(1)**, **nchar(1)** or **char(1)**) that is used as separator for concatenated strings.
48
+
Is a single character [expression](../../t-sql/language-elements/expressions-transact-sql.md) of any character type (for example, **nvarchar(1)**, **varchar(1)**, **nchar(1)**, or **char(1)**) that is used as separator for concatenated strings.
51
49
52
50
## Return Types
53
51
Returns a single-column table with fragments. The name of the column is **value**. Returns **nvarchar** if any of the input arguments are either **nvarchar** or **nchar**. Otherwise returns **varchar**. The length of the return type is the same as the length of the string argument.
54
52
55
53
## Remarks
56
-
**STRING_SPLIT** takes a string that should be divided and the separator that will be used to divide string. It returns a single-column table with substrings. For example, the following statement `SELECT value FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ');` using the space character as the separator, returns following result table:
54
+
**STRING_SPLIT** takes a string that should be divided and the separator that will be used to divide string. It returns a single-column table with substrings. For example, the following statement `SELECT value FROM STRING_SPLIT('Lorem ipsum dolor sit amet.', ' ');` using the space character as the separator, returns following result table:
STRING_SPLIT will return empty string if there is nothing between separator. Condition RTRIM(value) <> '' will remove empty tokens.
81
+
STRING_SPLIT will return empty string if there is nothing between separator. Condition RTRIM(value) <> '' will remove empty tokens.
86
82
87
-
### B. Split commaseparated value string in a column
88
-
Product table has a column with comma-separate list of tags shown in the following example:
83
+
### B. Split comma-separated value string in a column
84
+
Product table has a column with comma-separate list of tags shown in the following example:
89
85
90
86
|ProductId|Name|Tags|
91
87
|---------------|----------|----------|
92
88
|1|Full-Finger Gloves|clothing,road,touring,bike|
93
89
|2|LL Headset|bike|
94
90
|3|HL Mountain Frame|bike,mountain|
95
91
96
-
Following query transforms each list of tags and joins them with the original row:
92
+
Following query transforms each list of tags and joins them with the original row:
97
93
98
-
```
94
+
```sql
99
95
SELECT ProductId, Name, value
100
96
FROM Product
101
97
CROSS APPLY STRING_SPLIT(Tags, ',');
@@ -114,9 +110,9 @@ FROM Product
114
110
|3|HL Mountain Frame|mountain|
115
111
116
112
### C. Aggregation by values
117
-
Users must create a report that shows the number of products per each tag, ordered by number of products, and to filter only the tags with more than 2 products.
113
+
Users must create a report that shows the number of products per each tag, ordered by number of products, and to filter only the tags with more than two products.
118
114
119
-
```
115
+
```sql
120
116
SELECT value as tag, COUNT(*) AS [Number of articles]
121
117
FROM Product
122
118
CROSS APPLY STRING_SPLIT(Tags, ',')
@@ -126,19 +122,19 @@ ORDER BY COUNT(*) DESC;
126
122
```
127
123
128
124
### D. Search by tag value
129
-
Developers must create queries that find articles by keywords. They can use following queries:
125
+
Developers must create queries that find articles by keywords. They can use following queries:
130
126
131
-
To find products with a single tag (clothing):
127
+
To find products with a single tag (clothing):
132
128
133
-
```
129
+
```sql
134
130
SELECT ProductId, Name, Tags
135
131
FROM Product
136
132
WHERE'clothing'IN (SELECT value FROM STRING_SPLIT(Tags, ','));
137
133
```
138
134
139
-
Find products with two specified tags (clothing and road):
135
+
Find products with two specified tags (clothing and road):
140
136
141
-
```
137
+
```sql
142
138
143
139
SELECT ProductId, Name, Tags
144
140
FROM Product
@@ -148,30 +144,30 @@ WHERE EXISTS (SELECT *
148
144
```
149
145
150
146
### E. Find rows by list of values
151
-
Developers must create a query that finds articles by a list of ids. They can use following query:
147
+
Developers must create a query that finds articles by a list of IDs. They can use following query:
152
148
153
-
```
149
+
```sql
154
150
SELECT ProductId, Name, Tags
155
151
FROM Product
156
152
JOIN STRING_SPLIT('1,2,3',',')
157
153
ON value = ProductId;
158
154
```
159
155
160
-
This is replacement for common anti-pattern such as creating a dynamic SQL string in application layer or [!INCLUDE[tsql](../../includes/tsql-md.md)], or by using LIKE operator:
156
+
This is replacement for common anti-pattern such as creating a dynamic SQL string in application layer or [!INCLUDE[tsql](../../includes/tsql-md.md)], or by using LIKE operator:
0 commit comments