65.9K
CodeProject 正在变化。 阅读更多。
Home

SQL Server 如何删除记录

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (14投票s)

2012年4月28日

CPOL

2分钟阅读

viewsIcon

21014

SQL Server 如何删除记录

引言

我惊讶于许多开发人员不知道 SQL Server 不会立即执行 DELETE 命令,而是会定期在后台线程中执行一个名为 GHOST CLEANUP 的进程。当事务请求删除行时,该行只是被标记为“幽灵”(ghosted),然后由后台进程实际删除数据。 这样可以提高性能,并且在 ROLLBACK 时可以减少工作量。 在系统表 sys.dm_exec_requests 中,您可以定期看到 GHOST CLEANUP 作为命令出现。

所以,让我们看看 SQL Server 在执行时实际做了什么:

DELETE FROM MyTable WHERE PrimaryKeyField = some_value

首先,让我们创建一个测试表并插入几条记录。

CREATE TABLE [dbo].[DeleteInternals](
 [Id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
 [Name] [char](4) NOT NULL
)
GO
insert into DeleteInternals([Name]) values('Row1')
insert into DeleteInternals([Name]) values('Row2')
insert into DeleteInternals([Name]) values('Row3')
insert into DeleteInternals([Name]) values('Row4')

为了发现表的内部结构,我们将使用未文档化的命令 DBCC IND 和 DBCC PAGE,这些命令在 SQL Server 内部被广泛使用,但它们没有文档且不受支持,这意味着您使用它们需要自行承担风险。

要找出使用 DBCC PAGE 查看哪些页面 ID,我们执行:

DBCC IND(TestDatabase, DeleteInternals, 1) 

输出中对我们来说重要的字段是:

  • PageFID - 页面的文件 ID
  • PagePID - 文件中的页码
  • OBjectID - 页面所属对象的 ID
  • IndexID - 页面所属索引的 ID
  • PageType - 其中 1 = 数据页,2 = 索引页
  • IndexLevel - 由于 SQL Server 在 B 树中使用双向链表来存储索引,因此数据实际上是聚簇索引的叶子级别(level 0)。

为了将输出返回到控制台,我们需要启用 T3604:

DBCC TRACEON(3604)
GO
DBCC PAGE(TestDatabase, 1,399,1) 

这是此命令的输出:

对于我们的示例,以下记录很重要(用红色方框标记):

  • m_slotCnt = 4 - 显示页面上的记录数
  • m_GhostRecCnt = 0 - “幽灵”记录的数量
  • RecordType = PRIMARY_RECORD 用于 Slot1,其中包含稍后将被删除的“Row2”数据
  • Row - Offset 表 - 所有记录的偏移量。

执行 DELETE 命令后,我们将再次查看页面结构。 但是,为了防止 GHOST CLEANUP 进程执行并清理我们的页面,我们将把 DELETE 命令包含在一个事务中,并且在一段时间内不提交该事务:

begin transaction 
delete from DeleteInternals where Id = 2 

让我们看一下页面内容

DBCC PAGE(TestDatabase, 1,399,1) 

我们仍然有 4 条记录 (m_slotCnt),但现在我们可以看到我们有一条“幽灵”记录,m_ghostRecCnt = 1。 该记录正是我们的“Row2”,现在被标记为 GHOST_DATA_RECORD (RecordType)。 Row - Offset 表保持不变。

提交事务后,通过执行:

commit 

并再次检查页面结构:

DBCC PAGE(TestDatabase, 1,399,1) 

我们看到,提交事务后,记录数等于 3 (m_slotCnt = 3),并且“幽灵”记录数等于 0 (m_ghostRecCnt = 0)

此外,Row - Offset 表显示所有三条记录,但您会注意到它们的偏移量与之前相同,即在执行删除命令之前,这意味着 SQL Server 没有压缩页面。 我们下次再讨论这个问题。

© . All rights reserved.