Estrategia de división de nodo B-tree en SQL Server para un valor monotónicamente creciente


8

Considere un índice de árbol B en un valor que siempre aumentará monotónicamente, por ejemplo, una columna de tipo IDENTIDAD. Con una implementación convencional de árbol B, cada vez que un nodo está lleno, se dividirá 50% / 50% y terminaremos con un árbol B en el que (casi) todos los nodos estarán llenos solo un 50%.

Sé que Oracle descubre cuándo un valor aumenta constantemente y, en estos casos, Oracle realiza una división del 90% / 10%. De esa manera, (casi) todos los nodos estarán llenos al 90% y se obtendrá una mejor utilización de la página para estos casos, bastante comunes.

No he podido encontrar documentación para una característica similar en SQL Server. Sin embargo, he realizado dos experimentos en los que inserté N enteros aleatorios y N enteros consecutivos en un índice, respectivamente. El primer caso usó muchas más páginas que el segundo.

¿SQL Server proporciona una funcionalidad similar? Si es así: ¿puede indicarme alguna documentación sobre esta función?

ACTUALIZACIÓN: Según los experimentos que se proporcionan a continuación, parece que los nodos hoja se mantienen sin dividir y los nodos internos se dividen en un 50% / 50%. Eso hace que los árboles B en claves crecientes sean más compactos que en claves aleatorias. Sin embargo, el enfoque de 90% / 10% de Oracle es aún mejor, y todavía busco alguna documentación oficial que pueda verificar el comportamiento visto en los experimentos.


Parece que una respuesta aceptable a esta pregunta probablemente sea alguna documentación que enumere todos los diversos tipos de división de páginas que pueden ocurrir y cuándo pueden ocurrir. Actualmente no tengo conocimiento de tal recurso, pero tal vez alguien aquí esté ...
Martin Smith

Respuestas:


4

Si agrega una fila al final del índice, solo asignará una nueva página para la fila en lugar de dividir la página final actual. A continuación se encuentra evidencia experimental de esto (usa la %%physloc%%función que requiere SQL Server 2008). Vea también la discusión aquí .

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

Devoluciones (sus resultados variarán)

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

Sin embargo, esto solo parece aplicarse a los nodos hoja. Esto se puede ver ejecutando lo siguiente y ajustando el TOPvalor. Para mí, 622/623fue el punto de corte entre requerir una y dos páginas de primer nivel (¿podría variar si tiene habilitado el aislamiento de instantáneas?). Divide la página de manera equilibrada, lo que genera un desperdicio de espacio en este nivel.

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

Gracias. Pero tenga en cuenta que estoy preguntando por el comportamiento de los nodos de índice del árbol B, no por las páginas de la tabla. Interesante lectura sin embargo. :-)
someName

1
@someName: las páginas de la tabla son los nodos hoja del índice agrupado creado implícitamente por PRIMARY KEY.
Martin Smith

Ah, ya veo. Esa estrategia de inserción es ciertamente eficiente en espacio. Pero no veo cómo encaja esto en la estructura del árbol B: con la estrategia "agregar a la nueva página en lugar de dividir", terminamos con una larga lista vinculada, y no un árbol B. ¿Cómo se recuperan los valores específicos utilizando solo un número logarítmico de búsquedas (E / S) en esta lista vinculada?
someName

Este es solo el nivel del nodo hoja. Tan pronto como el nivel del nodo hoja tenga más de 1 página, habrá otro nivel arriba. Puede usar DBCC INDy sys.dm_db_index_physical_statspara ver información sobre estos.
Martin Smith

Pero cada vez que uno de los nodos no hoja esté lleno, me dividiré. ¿Y esa división, supongo, es 50% / 50%? ¿O 90% / 10% como lo hace Oracle?
someName
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.