Перебалансировано ли B-Tree при удалении данных из таблицы SQL Server с кластеризованным индексом?

10

У меня есть таблица в базе данных SQL Server с кластеризованным индексом по первичному ключу. Таблица имеет 1 миллион строк. Если я удаляю 10K строк из таблицы, реструктурируется ли индекс во время операции удаления?

Операция удаления является частью хранимой процедуры. В то же время, более чем один клиент может выполнять хранимую процедуру, однако каждый отдельный прогон будет удалять свой собственный набор строк (уникально идентифицируемых первичным ключом). Я получаю блокировку блокировки ключа (типа U), когда несколько клиентов выполняет процедуру. Блокирующая блокировка принадлежит строке из той же таблицы и не является частью какой-либо одновременно выполняемой транзакции. Не должно быть никаких блокировок, поскольку каждый прогон пытается удалить свой собственный набор строк. Повышение блокировки не происходит, поскольку оно отключено.

Я подозреваю, что операция удаления должна приводить к перебалансировке индекса, и, следовательно, в процессе реструктуризации может потребоваться блокировка ключа в любой строке таблицы.

Буду очень признателен за любое мнение по этому поводу.

Jayesh
источник
Хороший вопрос и хорошее предположение. Да, при удалении записи индекс перестраивается. Во время перестроения таблица процессов блокируется, и другой пользователь не сможет получить доступ к этой таблице. stackoverflow.com/questions/6309614/…
KumarHarsh
4
НЕТ, удаление строк в кластерном индексе не приводит к перестроению индекса. Вы также можете опубликовать запрос, используемый для удаления данных. Блокировка U происходит, когда запрос пытается найти данные, которые будут удалены, и, наконец, блокирует исключительно строки для его удаления.
Шэнки
2
Когда происходит удаление, это создает «дыру», или вы можете сказать пробел, поскольку данные были удалены из кластерного индекса. Это может создать низкую плотность страницы и может рассматриваться как фрагментация. Когда вставка происходит в CI, она будет заполнять записи с правой стороны, и поэтому пространство может никогда не заполняться. Но SQL Server не собирается автоматически удалять это пространство. Вы должны перестроить индекс или реорганизовать, чтобы заполнить это пространство. Нет НИКАКОГО
ребалансирования
1
@jayesh Я не вижу, как порядок узлов в дереве связан с перебалансировкой. B-дерево может быть несбалансированным (из-за вставок или удалений). Порядок узлов в этих случаях не меняется. Это просто несбалансированное дерево.
ypercubeᵀᴹ
1
@jayesh Я думаю, что вам может пригодиться чтение некоторых документов по MSSQL, так как я думаю, что используемая вами терминология сбивает вас с толку и некоторых из нас.
LowlyDBA

Ответы:

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-дереву с практически всеми данными на одной стороне.

Форрест
источник
спасибо за ясное и краткое объяснение и демонстрационный код. Я попробую это. Я приму этот ответ. Я все еще пытаюсь понять, почему удаление несвязанного набора строк вызывает блокировку таблицы с кластерным индексом.
Джаеш