SQL Server中的B树节点拆分策略可单调增加价值


8

考虑一个将始终单调增加的值的B树索引,例如IDENTITY类型的列。使用传统的B树实现,每当一个节点满时,它将被拆分50%/ 50%,最后我们得到一个B树,其中几乎所有节点都只有50%满。

我知道Oracle发现何时值会不断增加,在这种情况下,Oracle会执行90%/ 10%的拆分。这样,(几乎)所有节点都将充满90%的数据,对于这些非常常见的情况,页面利用率要高得多。

我无法在SQL Server中找到类似功能的文档。但是,我进行了两个实验,分别在索引中插入了N个随机整数和N个连续整数。前一种情况使用了更多的页面,而后者则使用了更多页面。

SQL Server是否提供类似的功能?如果是这样:您能指出我一些有关此功能的文档吗?

更新: 通过下面提供的实验,叶节点似乎保持未分裂状态,内部节点分裂了50%/ 50%。这使得递增键上的B树比随机键上的树更紧凑。但是,Oracle提出的90%/ 10%的方法甚至更好,我仍然在寻找一些官方文档来验证实验中看到的行为。


对于这个问题,似乎可以接受的答案可能是一些文档,其中列出了可能发生的所有各种类型的页面拆分以及何时发生。我目前不知道这种资源,但也许有人在...
Martin Smith

Answers:


4

如果它在索引末尾添加一行,则只会为该行分配一个新页面,而不是拆分当前的末尾页面。下面是对此的实验证据(使用%%physloc%%需要SQL Server 2008 的功能)。另请参见此处的讨论

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

退货(您的结果会有所不同)

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

不过,这似乎仅适用于叶节点。通过运行以下内容并调整TOP值可以看出这一点。对我来说,622/623是要求一个和两个第一级页面之间的切入点(如果启用了快照隔离功能,可能会有所不同吗?)。它确实以平衡的方式拆分页面,导致该级别的空间浪费。

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

谢谢。但是请注意,我要的是B树索引节点的行为-不是表页。虽然有趣的阅读。:-)
someName 2011年

1
@someName-表页面是由隐式创建的聚簇索引的叶节点PRIMARY KEY
马丁·史密斯

知道了 该插入策略当然是节省空间的。但是我看不到它如何适合B树结构:使用“添加到新页面而不是拆分”策略,我们最终得到的是长链表,而不是B树。如何仅使用此链接列表中对数的查找(I / O)来检索特定值?
someName 2011年

这只是叶子节点级别。一旦叶子节点级别超过一页,就会在上面有另一个级别。您可以使用DBCC INDsys.dm_db_index_physical_stats查看有关这些的信息。
马丁·史密斯,

但是只要非叶节点之一已满,我就会被分割。我猜那是50%/ 50%?还是Oracle的90%/ 10%?
someName 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.