Strategi B-tree node split dalam SQL Server untuk meningkatkan nilai secara monoton

8

Pertimbangkan indeks B-tree pada nilai yang akan selalu meningkat secara monoton, misalnya kolom tipe IDENTITY. Dengan implementasi B-tree konvensional, setiap kali node penuh, ia akan dibagi 50% / 50% dan kita berakhir dengan B-tree di mana (hampir) semua node akan hanya 50% penuh.

Saya tahu bahwa Oracle menemukan ketika nilai semakin meningkat dan dalam kasus ini Oracle melakukan split 90% / 10% sebagai gantinya. Dengan begitu, (hampir) semua node akan 90% penuh dan pemanfaatan halaman yang jauh lebih baik diperoleh untuk kasus-kasus ini, sangat umum.

Saya belum dapat menemukan dokumentasi untuk fitur serupa di SQL Server. Namun, saya telah melakukan dua percobaan di mana saya memasukkan N bilangan bulat acak, dan N bilangan bulat berturut-turut dalam indeks, masing-masing. Kasus pertama menggunakan halaman jauh lebih banyak yang terakhir.

Apakah SQL Server menyediakan fungsionalitas yang serupa? Jika demikian: dapatkah Anda mengarahkan saya ke beberapa dokumentasi tentang fitur ini?

PEMBARUAN: Tampaknya, dari percobaan yang diberikan di bawah ini, bahwa simpul daun dijaga agar tidak dipisahkan dan simpul internal terpecah 50% / 50%. Itu membuat B-tree pada meningkatkan kunci lebih kompak daripada pada kunci acak. Namun, pendekatan 90% / 10% oleh Oracle bahkan lebih baik, dan saya masih mencari beberapa dokumentasi resmi yang dapat memverifikasi perilaku yang terlihat dalam percobaan.

someName
sumber
Tampaknya jawaban yang dapat diterima untuk pertanyaan ini mungkin adalah beberapa dokumentasi yang mencantumkan semua berbagai jenis pemisah halaman yang dapat terjadi dan kapan bisa terjadi. Saat ini saya tidak mengetahui sumber daya seperti itu tetapi mungkin seseorang di sini ...
Martin Smith

Jawaban:

4

Jika menambahkan baris di akhir indeks, itu hanya akan mengalokasikan halaman baru untuk baris daripada membagi halaman akhir saat ini. Bukti eksperimental untuk ini di bawah ini (menggunakan %%physloc%%fungsi yang membutuhkan SQL Server 2008). Lihat juga diskusi di sini .

CREATE TABLE T
(
id int identity(1,1) PRIMARY KEY,
filler char(1000)
)
GO

INSERT INTO T
DEFAULT VALUES
GO 7

GO
SELECT sys.fn_PhysLocFormatter(%%physloc%%)
FROM T

GO

INSERT INTO T
DEFAULT VALUES

GO

SELECT sys.fn_PhysLocFormatter(%%physloc%%)
FROM T
GO

DROP TABLE T

Pengembalian (Hasil Anda akan bervariasi)

(1:173:0) /*File:Page:Slot*/
(1:173:1)
(1:173:2)
(1:173:3)
(1:173:4)
(1:173:5)
(1:173:6)
(1:110:0) /*Final insert is on a new page*/

Ini tampaknya hanya berlaku untuk node daun. Ini dapat dilihat dengan menjalankan di bawah ini dan menyesuaikan TOPnilainya. Bagi saya 622/623adalah titik potong antara membutuhkan satu dan dua halaman tingkat pertama (mungkin berbeda jika Anda memiliki isolasi snapshot diaktifkan?). Itu membagi halaman secara seimbang yang mengarah ke ruang terbuang pada level ini.

USE tempdb;

CREATE TABLE T2
(
id int identity(1,1) PRIMARY KEY CLUSTERED,
filler char(8000)
)

INSERT INTO T2(filler)
SELECT TOP 622 'A'
FROM master..spt_values v1,  master..spt_values v2

DECLARE @index_info  TABLE
(PageFID  VARCHAR(10), 
  PagePID VARCHAR(10),   
  IAMFID   tinyint, 
  IAMPID  int, 
  ObjectID  int,
  IndexID  tinyint,
  PartitionNumber tinyint,
  PartitionID bigint,
  iam_chain_type  varchar(30),    
  PageType  tinyint, 
  IndexLevel  tinyint,
  NextPageFID  tinyint,
  NextPagePID  int,
  PrevPageFID  tinyint,
  PrevPagePID int, 
  Primary Key (PageFID, PagePID));

INSERT INTO @index_info 
    EXEC ('DBCC IND ( tempdb, T2, -1)'  ); 

DECLARE @DynSQL nvarchar(max) = 'DBCC TRACEON (3604);'
SELECT @DynSQL = @DynSQL + '
DBCC PAGE(tempdb, ' + PageFID + ', ' + PagePID + ', 3); '
FROM @index_info     
WHERE IndexLevel = 1

SET @DynSQL = @DynSQL + '
DBCC TRACEOFF(3604); '

EXEC(@DynSQL)


DROP TABLE T2
Martin Smith
sumber
Terima kasih. Tetapi perhatikan, bahwa saya meminta perilaku node indeks B-tree - bukan halaman tabel. Baca menarik. :-)
someName
1
@someName - Halaman tabel adalah simpul daun dari indeks berkerumun yang secara implisit dibuat oleh PRIMARY KEY.
Martin Smith
Ah, begitu. Strategi penyisipan itu tentu saja hemat ruang. Tapi saya gagal melihat bagaimana ini cocok dengan struktur B-tree: Dengan strategi "tambah-ke-halaman-bukan-pemisahan" kita berakhir dengan daftar yang ditautkan lama, dan bukan B-tree. Bagaimana nilai-nilai spesifik diambil hanya dengan jumlah pencarian logaritmik (I / O) dalam daftar tertaut ini?
someName
Ini hanya tingkat simpul daun. Segera setelah level node daun memiliki lebih dari 1 halaman, akan ada level lain di atas. Anda dapat menggunakan DBCC INDdan sys.dm_db_index_physical_statsmelihat info tentang ini.
Martin Smith
Tetapi setiap kali salah satu node non-daun penuh saya akan dibagi. Dan pemisahan itu, saya kira, adalah 50% / 50%? Atau 90% / 10% seperti Oracle yang melakukannya?
someName