Чи B-Tree повторно врівноважується під час видалення даних із таблиці SQL Server із кластерним індексом?


10

У мене є таблиця в базі даних SQL Server з кластерним індексом на первинному ключі. У таблиці 1 мільйон рядків. Якщо я видаляю 10K рядків з таблиці, чи індексується реструктуризація під час операції видалення?

Операція видалення є частиною збереженої процедури. За один раз, більше ніж один клієнт може виконати збережену процедуру, однак кожен окремий запуск видалить власний набір рядків (унікально визначений первинним ключем). Я блокую ключ блокування ключа (типу U), коли процедура виконує кілька клієнтів. Блокування блокатора належить до рядка з тієї ж таблиці, і він не є частиною жодної з одночасно запущених транзакцій. Блокування не повинно бути, оскільки кожен запуск намагається видалити власний набір рядків. Ескалація блокування не відбувається, оскільки вона вимкнена.

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

Я дуже вдячний будь-якій думці з цього приводу.


Приємне запитання і приємна здогадка. Так, коли ви видаляєте запис, індекс відновляється. Під час процесу відновлення таблиця заблокована, а інший користувач не зможе отримати доступ до цієї таблиці. 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-дерево з практично всіма даними на одній стороні.


дякую за чітке і стисле пояснення та демонстраційний код. Я спробую це. Я прийму цю відповідь. Я все ще намагаюся розібратися, чому видалення на роз'єднаному наборі рядків викликає блокування таблиці з кластерним індексом.
jayesh
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.