Stratégie de division des nœuds de l'arborescence B dans SQL Server pour augmenter la valeur de façon monotone

8

Considérons un index B-tree sur une valeur qui augmentera toujours de façon monotone, par exemple une colonne de type IDENTITY. Avec une implémentation d'arbre B conventionnelle, chaque fois qu'un nœud est plein, il sera divisé à 50% / 50% et nous nous retrouvons avec un arbre B dans lequel (presque) tous les nœuds ne seront pleins qu'à 50%.

Je sais qu'Oracle découvre quand une valeur est en constante augmentation et dans ces cas, Oracle effectue à la place une répartition 90% / 10%. De cette façon, (presque) tous les nœuds seront remplis à 90% et une utilisation de la page bien meilleure est obtenue pour ces cas, assez courants.

Je n'ai pas pu trouver de documentation pour une fonctionnalité similaire dans SQL Server. Cependant, j'ai effectué deux expériences dans lesquelles j'ai inséré N entiers aléatoires et N entiers consécutifs dans un index, respectivement. Le premier cas utilisait bien plus de pages que le second.

SQL Server fournit-il une fonctionnalité similaire? Si oui: pouvez-vous m'indiquer une documentation sur cette fonctionnalité?

MISE À JOUR: Il semble, par les expériences fournies ci-dessous, que les nœuds foliaires sont maintenus non divisés et les nœuds internes sont divisés à 50% / 50%. Cela rend les arbres B sur les clés croissantes plus compacts que sur les clés aléatoires. Cependant, l'approche 90% / 10% par Oracle est encore meilleure, et je cherche toujours de la documentation officielle qui peut vérifier le comportement vu dans les expériences.

someName
la source
Il semble qu'une réponse acceptable à cette question serait probablement une documentation qui répertorie tous les différents types de fractionnement de pages qui peuvent se produire et quand ils peuvent se produire. Je ne suis pas actuellement au courant d'une telle ressource mais peut-être que quelqu'un ici est ...
Martin Smith

Réponses:

4

S'il ajoute une ligne à la fin de l'index, il allouera simplement une nouvelle page à la ligne plutôt que de diviser la page de fin actuelle. Les preuves expérimentales de ceci sont ci-dessous (utilise la %%physloc%%fonction qui nécessite SQL Server 2008). Voir également la discussion ici .

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

Retours (vos résultats varieront)

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

Cela ne semble cependant s'appliquer qu'aux nœuds feuilles. Cela peut être vu en exécutant ce qui suit et en ajustant la TOPvaleur. Pour moi, 622/623c'était le point de coupure entre la nécessité d'une et deux pages de premier niveau (peut varier si vous avez activé l'isolement de l'instantané?). Il divise la page de manière équilibrée, ce qui entraîne un gaspillage d'espace à ce niveau.

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
la source
Merci. Mais remarquez que je demande le comportement des nœuds d'index B-tree - pas les pages de table. Lecture intéressante cependant. :-)
someName
1
@someName - Les pages de table sont les nœuds terminaux de l'index cluster créé implicitement par le PRIMARY KEY.
Martin Smith
Ah, je vois. Cette stratégie d'insertion est certainement peu encombrante. Mais je ne vois pas comment cela s'intègre dans la structure de l'arborescence B: avec la stratégie "ajouter à une nouvelle page au lieu de fractionner", nous nous retrouvons avec une longue liste chaînée, et non une arborescence B. Comment les valeurs spécifiques sont-elles récupérées en utilisant uniquement un nombre logarithmique de recherches (E / S) dans cette liste chaînée?
someName
Ce n'est que le niveau du nœud feuille. Dès que le niveau du nœud feuille a plus d'une page, il y aura un autre niveau au-dessus. Vous pouvez utiliser DBCC INDet sys.dm_db_index_physical_statspour voir des informations à ce sujet.
Martin Smith
Mais chaque fois que l'un des nœuds non-feuilles est plein, je suis divisé. Et cette répartition, je suppose, est de 50% / 50%? Ou 90% / 10% comme le fait Oracle?
someName