Apakah B-Tree kembali seimbang selama penghapusan data dari tabel SQL Server dengan indeks berkerumun?

10

Saya punya tabel dalam database SQL Server dengan indeks berkerumun pada kunci utama. Tabel memiliki 1 juta baris. Jika saya menghapus 10K baris dari tabel, apakah indeks bisa direstrukturisasi selama operasi penghapusan dilakukan?

Operasi penghapusan adalah bagian dari prosedur tersimpan. Pada suatu waktu, lebih dari satu klien dapat menjalankan prosedur yang tersimpan, namun setiap proses individual akan menghapus rangkaian barisnya sendiri (diidentifikasi secara unik oleh kunci primer). Saya mendapatkan pemblokiran pada kunci kunci (tipe U) ketika beberapa klien menjalankan prosedur. Kunci pemblokir milik baris dari tabel yang sama dan itu bukan bagian dari transaksi yang berjalan bersamaan. Seharusnya tidak ada pemblokiran karena setiap proses mencoba menghapus kumpulan barisnya sendiri. Eskalasi kunci tidak terjadi karena dimatikan.

Saya menduga, operasi penghapusan harus menyebabkan indeks untuk menyeimbangkan kembali dan karenanya selama proses restrukturisasi dapat mengambil kunci kunci pada setiap baris tabel.

Saya akan sangat menghargai pendapat tentang ini.

jayesh
sumber
Pertanyaan yang bagus dan tebakan yang bagus. Ya, ketika Anda menghapus catatan, indeks dibangun kembali. Selama proses membangun kembali tabel terkunci dan pengguna lain tidak akan dapat mengakses tabel itu. stackoverflow.com/questions/6309614/...
KumarHarsh
4
TIDAK, penghapusan baris pada indeks berkerumun tidak menyebabkan indeks dibangun kembali. Bisakah Anda juga mengirim kueri yang digunakan untuk menghapus data. Kunci U muncul ketika kueri mencoba menemukan data yang akan dihapus dan akhirnya secara eksklusif mengunci baris untuk menghapusnya.
Shanky
2
Ketika penghapusan terjadi, ia menciptakan "lubang" atau Anda dapat mengatakan spasi karena data dihapus dari indeks berkerumun. Ini dapat membuat kepadatan halaman rendah dan dapat dianggap sebagai fragmentasi. Ketika memasukkan terjadi pada CI itu akan mengisi catatan di sisi kanan dan karena ini ruang mungkin tidak pernah diisi. Tetapi SQL Server tidak secara otomatis akan menghapus ruang ini. Anda harus membangun kembali indeks atau mengatur ulang untuk mengisi ruang ini. TIDAK ada penyeimbangan kembali
Shanky
1
@ Jayesh Saya tidak melihat bagaimana urutan node dalam pohon berkaitan dengan penyeimbangan kembali. Pohon-B dapat tidak seimbang (baik karena menyisipkan atau menghapus). Urutan simpul tidak berubah dalam kasus ini. Itu hanya pohon yang tidak seimbang.
ypercubeᵀᴹ
1
@ Jayesh Saya pikir Anda dapat mengambil manfaat dari membaca beberapa dokumen MSSQL, karena saya pikir terminologi yang Anda gunakan membingungkan Anda dan sebagian dari kita.
LowlyDBA

Jawaban:

3

Untuk menjawab pertanyaan dalam judul, apakah pohon-B rebalanced selama penghapusan, jawabannya tampaknya tidak, setidaknya dalam kasus uji minimal berikut.

Demo berikut menjalankan perintah yang sebaiknya digunakan untuk lingkungan pengujian.

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

Demo ini menunjukkan bahwa penghapusan dapat menghasilkan b-tree yang sangat tidak seimbang, dengan hampir semua data di satu sisi.

Forrest
sumber
terima kasih atas penjelasan dan kode demo yang jelas dan ringkas. Saya akan mencoba ini. Saya akan menerima jawaban ini. Saya masih mencoba mencari tahu mengapa menghapus pada set baris yang terpisah menyebabkan pemblokiran di atas meja dengan indeks berkerumun.
jayesh