从具有聚集索引的SQL Server表删除数据期间,B树是否重新平衡?


10

我在SQL Server数据库中有一个表,在主键上有聚簇索引。该表有100万行。如果我从表中删除了1万行,执行删除操作期间索引是否会被重组?

删除操作是存储过程的一部分。一次,一个以上的客户端可以执行该存储过程,但是每个单独的运行都将删除其自己的一组行(由主键唯一标识)。当多个客户端执行该过程时,我将无法使用(U型)键锁。阻止程序锁属于同一表中的一行,并且不属于任何同时运行的事务。不应有任何阻塞,因为每次运行都试图删除自己的行集。由于已关闭锁升级,因此不会发生。

我怀疑,删除操作一定会导致索引重新平衡,因此在重组过程中,它可能会对表的任何行进行键锁定。

我对此表示感谢。


好问题,好猜测。是的,删除记录时,将重新建立索引。在重建过程中,表被锁定,其他用户将无法访问该表。stackoverflow.com/questions/6309614/…–
KumarHarsh

4
否,删除聚集索引上的行不会导致索引重建。您还可以发布用于删除数据的查询吗?当查询试图查找将被删除的数据时,U锁就会出现,最后将其排他地锁定以将其删除。
Shanky

2
删除发生时,会创建一个“空洞”,或者您可以说是空格,因为数据已从聚集索引中删除。这可能会导致低页面密度,并可以视为碎片。当在CI上发生插入操作时,它将在右侧填充记录,因此可能永远不会填充该空间。但是SQL Server不会自动删除该空间。您必须重建索引或重新组织以填充此空间。没有这样的重新平衡
Shanky

1
@jayesh我看不到树中节点的顺序与重新平衡有何关系。B树可能是不平衡的(由于插入或删除)。在这些情况下,节点顺序不变。它只是一棵不平衡的树。
ypercubeᵀᴹ

1
@jayesh我认为您可能会从阅读一些MSSQL文档中受益,因为我认为您使用的术语使您和我们中的一些人感到困惑。
LowlyDBA '18

Answers:


3

为了回答标题中的问题,即删除期间B树是否重新平衡,至少在以下最小测试用例中,答案似乎是否定的。

以下演示将运行最适合测试环境的命令。

--create table and fill it
DROP TABLE IF EXISTS bunchesofints
CREATE TABLE bunchesofints (
thisisanint INT PRIMARY KEY CLUSTERED,
junkrow CHAR(1000) NOT NULL
)

INSERT dbo.bunchesofints
SELECT TOP 5000
ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) AS thisisanint,
REPLICATE('a',1000) AS junkrow
FROM sys.all_objects a1
CROSS JOIN sys.all_objects a2


--with this query we can see all the non-leaf pages of the b-tree, plus the IAM
SELECT allocated_page_page_id, page_type_desc, page_level, is_allocated, next_page_page_id, previous_page_page_id
FROM sys.dm_db_database_page_allocations(DB_ID(),OBJECT_ID('dbo.bunchesofints'),NULL,NULL,'DETAILED')
WHERE page_type != 1
GO

--Ok, let's delete most of the rows
;WITH CTE AS (
    SELECT TOP (4500) *
    FROM dbo.bunchesofints
    ORDER BY thisisanint DESC
)

DELETE 
FROM CTE
GO

--Hmm, still have 3 non-leaf index pages
SELECT allocated_page_page_id, page_type_desc, page_level, is_allocated, next_page_page_id, previous_page_page_id
FROM sys.dm_db_database_page_allocations(DB_ID(),OBJECT_ID('dbo.bunchesofints'),NULL,NULL,'DETAILED')
WHERE page_type != 1



--So, where are the rows?
--please note the assumption that your test database has a single file.
DECLARE @firstindexpage INT, @lastindexpage INT, @db INT = DB_ID()
SELECT @firstindexpage = MIN(previous_page_page_id), @lastindexpage = MAX(next_page_page_id)
FROM sys.dm_db_database_page_allocations(DB_ID(),OBJECT_ID('dbo.bunchesofints'),NULL,NULL,'DETAILED')
WHERE page_type = 2 AND page_level = 1

DBCC PAGE(@db,1,@firstindexpage,3) WITH TABLERESULTS
DBCC PAGE(@db,1,@lastindexpage,3) WITH TABLERESULTS

该演示演示了删除操作会产生非常不平衡的b树,实际上所有数据都在一侧。


感谢您简洁明了的说明和演示代码。我会尝试的。我会接受这个答案。我仍在尝试弄清楚为什么对不相交的行集进行删除会导致对具有聚集索引的表造成阻塞。
jayesh
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.