Wird B-Tree beim Löschen von Daten aus der SQL Server-Tabelle mit einem Clustered-Index neu ausgeglichen?

10

Ich habe eine Tabelle in einer SQL Server-Datenbank mit einem Clustered-Index für den Primärschlüssel. Die Tabelle enthält 1 Million Zeilen. Wenn ich 10K-Zeilen aus der Tabelle lösche, wird der Index während des Löschvorgangs umstrukturiert?

Der Löschvorgang ist Teil der gespeicherten Prozedur. Es kann gleichzeitig mehr als ein Client die gespeicherte Prozedur ausführen. Bei jedem einzelnen Lauf werden jedoch eigene Zeilen gelöscht (die durch den Primärschlüssel eindeutig identifiziert werden). Ich bekomme eine Blockierung der Schlüsselsperre (vom Typ U), wenn mehrere Clients die Prozedur ausführen. Die Blockersperre gehört zu einer Zeile aus derselben Tabelle und ist nicht Teil einer der gleichzeitig ausgeführten Transaktionen. Es sollte keine Blockierung geben, da jeder Lauf versucht, seine eigenen Zeilen zu löschen. Die Eskalation der Sperre findet nicht statt, da sie deaktiviert ist.

Ich vermute, dass der Löschvorgang dazu führen muss, dass der Index neu ausgeglichen wird, und daher kann er während des Umstrukturierungsprozesses eine Schlüsselsperre für jede Zeile der Tabelle vornehmen.

Ich würde mich über jede Meinung dazu sehr freuen.

Jayesh
quelle
Schöne Frage und nette Vermutung. Ja, wenn Sie einen Datensatz löschen, wird der Index neu erstellt. Während des Wiederherstellungsprozesses ist die Tabelle gesperrt und andere Benutzer können nicht auf diese Tabelle zugreifen. stackoverflow.com/questions/6309614/…
KumarHarsh
4
NEIN, das Löschen von Zeilen im Clustered-Index führt nicht zur Neuerstellung des Index. Können Sie auch die Abfrage veröffentlichen, die zum Löschen der Daten verwendet wird? Die U-Sperre wird aktiviert, wenn die Abfrage versucht, Daten zu finden, die gelöscht werden sollen, und sperrt schließlich ausschließlich die Zeilen, um sie zu löschen.
Shanky
2
Wenn das Löschen erfolgt, wird ein "Loch" erstellt, oder Sie können Leerzeichen angeben, wenn die Daten aus dem Clustered-Index entfernt wurden. Dies kann zu einer geringen Seitendichte führen und kann als Fragmentierung betrachtet werden. Wenn das Einfügen in CI erfolgt, werden die Datensätze auf der rechten Seite gefüllt. Aus diesem Grund wird der Bereich möglicherweise nie gefüllt. SQL Server wird diesen Speicherplatz jedoch nicht automatisch entfernen. Sie müssen den Index neu erstellen oder neu organisieren, um diesen Bereich zu füllen. Es gibt keine Neuausrichtung als solche
Shanky
1
@ jayesh Ich sehe nicht, wie die Reihenfolge der Knoten in einem Baum mit dem Neuausgleich zu tun hat. Ein B-Baum kann unausgeglichen sein (entweder aufgrund von Einfügungen oder Löschungen). Die Knotenreihenfolge ändert sich in diesen Fällen nicht. Es ist nur ein unausgeglichener Baum.
Ypercubeᵀᴹ
1
@jayesh Ich denke, Sie können vom Lesen einiger MSSQL-Dokumente profitieren, da die von Ihnen verwendete Terminologie Sie und einige von uns verwirrt.
LowlyDBA

Antworten:

3

Um die Frage im Titel zu beantworten, ob der B-Baum während eines Löschvorgangs neu ausgeglichen wurde, scheint die Antwort zumindest im folgenden minimalen Testfall Nein zu sein.

In der folgenden Demo werden Befehle ausgeführt, die am besten für eine Testumgebung geeignet sind.

--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

Diese Demo zeigt, dass ein Löschvorgang einen sehr unausgeglichenen B-Baum mit praktisch allen Daten auf einer Seite erzeugen kann.

Wald
quelle
Vielen Dank für die klare und prägnante Erklärung und den Demo-Code. Ich werde das ausprobieren. Ich werde diese Antwort akzeptieren. Ich versuche immer noch herauszufinden, warum das Löschen bei nicht zusammenhängenden Zeilen eine Blockierung der Tabelle mit dem Clustered-Index verursacht.
Jayesh