Chiến lược phân chia nút cây B trong SQL Server để tăng giá trị đơn điệu


8

Xem xét một chỉ mục cây B trên một giá trị sẽ luôn tăng đơn điệu, ví dụ: một cột có kiểu IDENTITY. Với cách triển khai cây B thông thường, bất cứ khi nào một nút đầy, nó sẽ được chia 50% / 50% và chúng tôi kết thúc với cây B trong đó (gần như) tất cả các nút sẽ chỉ đầy 50%.

Tôi biết rằng Oracle phát hiện ra khi một giá trị ngày càng tăng và trong những trường hợp này, Oracle thực hiện phân chia 90% / 10% thay thế. Bằng cách đó, (gần như) tất cả các nút sẽ đầy 90% và sử dụng trang tốt hơn nhiều cho các trường hợp này, khá phổ biến.

Tôi chưa thể tìm thấy tài liệu cho một tính năng tương tự trong SQL Server. Tuy nhiên, tôi đã thực hiện hai thử nghiệm trong đó tôi chèn N số nguyên ngẫu nhiên và N số nguyên liên tiếp trong một chỉ mục, tương ứng. Các trường hợp trước sử dụng nhiều trang hơn sau này.

SQL Server có cung cấp chức năng tương tự không? Nếu vậy: bạn có thể chỉ cho tôi một số tài liệu về tính năng này không?

CẬP NHẬT: Dường như, bằng các thí nghiệm được cung cấp dưới đây, các nút lá được giữ nguyên không bị chia tách và các nút bên trong được chia 50% / 50%. Điều đó làm cho cây B trên các phím tăng nhỏ gọn hơn so với các phím ngẫu nhiên. Tuy nhiên, 90% / 10% -approach của Oracle thậm chí còn tốt hơn và tôi vẫn tìm kiếm một số tài liệu chính thức có thể xác minh hành vi được thấy trong các thử nghiệm.


Có vẻ như một câu trả lời chấp nhận được cho câu hỏi này có thể là một số tài liệu liệt kê tất cả các loại phân chia trang khác nhau có thể xảy ra và khi nào chúng có thể xảy ra. Hiện tại tôi không biết về một tài nguyên như vậy nhưng có lẽ ai đó ở đây là ...
Martin Smith

Câu trả lời:


4

Nếu nó thêm một hàng ở cuối chỉ mục, nó sẽ chỉ phân bổ một trang mới cho hàng thay vì chia trang cuối hiện tại. Bằng chứng thực nghiệm cho điều này là bên dưới (sử dụng %%physloc%%chức năng yêu cầu SQL Server 2008). Xem thêm các cuộc thảo luận ở đây .

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

Trả về (Kết quả của bạn sẽ thay đổi)

(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*/

Điều này chỉ xuất hiện để áp dụng cho các nút lá mặc dù. Điều này có thể được nhìn thấy bằng cách chạy bên dưới và điều chỉnh TOPgiá trị. Đối với tôi 622/623là điểm giới hạn giữa yêu cầu một và hai trang cấp đầu tiên (có thể thay đổi nếu bạn bật cách ly ảnh chụp nhanh?). Nó phân chia trang một cách cân bằng dẫn đến lãng phí không gian ở cấp độ này.

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

Cảm ơn. Nhưng lưu ý rằng tôi đang yêu cầu hành vi của các nút chỉ mục cây B - không phải các trang bảng. Thú vị đọc mặc dù. :-)
someName

1
@someName - Các trang bảng là các nút lá của chỉ mục được nhóm ngầm định tạo bởi PRIMARY KEY.
Martin Smith

Ah tôi thấy. Chiến lược chèn đó chắc chắn là không gian hiệu quả. Nhưng tôi không thấy cách này phù hợp với cấu trúc cây B: Với chiến lược "thêm vào trang mới thay vì chia tách", chúng tôi kết thúc với một danh sách dài được liên kết và không phải là cây B. Làm thế nào các giá trị cụ thể được truy xuất chỉ bằng số lần tra cứu logarit (I / O) trong danh sách được liên kết này?
someName

Đây chỉ là cấp độ nút lá. Ngay khi cấp độ nút lá có nhiều hơn 1 trang, sẽ có một cấp độ khác ở trên. Bạn có thể sử dụng DBCC INDsys.dm_db_index_physical_statsđể xem thông tin về những điều này.
Martin Smith

Nhưng bất cứ khi nào một trong các nút không có lá đầy đủ tôi sẽ bị chia. Và sự phân chia đó, tôi đoán là 50% / 50%? Hoặc 90% / 10% như Oracle làm điều đó?
someName
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.