Liste des pages ROW_OVERFLOW_DATA pour un tableau spécifique


11

J'essaie d'obtenir une liste de pages pour une table qui a des lignes avec ROW_OVERFLOW_DATA. Je peux obtenir la liste des pages allouées à partir du DMV non documenté sys.db_db_database_page_allocations, cependant, il ne semble pas y avoir de pages ROW_OVERFLOW_DATA répertoriées dans la sortie de ce DMV. Y a-t-il un autre DMV que je ne peux tout simplement pas localiser?

Exemple minimal, complet et (espérons-le!) Vérifiable:

USE tempdb;

IF OBJECT_ID(N'dbo.t', N'U') IS NOT NULL
DROP TABLE dbo.t;
GO

CREATE TABLE dbo.t
(
    rownum int NOT NULL IDENTITY(1,1)
        PRIMARY KEY CLUSTERED
    , on_row_data varchar(30) NOT NULL
        DEFAULT ('on_row_data')
    , off_row_data varchar(MAX) NOT NULL
        DEFAULT REPLICATE('A', 20000) --PLENTY BIG ENOUGH!
) WITH (DATA_COMPRESSION = NONE); --not compressing those pages!

INSERT INTO dbo.t DEFAULT VALUES;

DECLARE @ObjectID int = (SELECT o.object_id FROM sys.objects o WHERE o.name = 't');
DECLARE @PageID int;
DECLARE @PageTypeDesc varchar(100);

SELECT FileID = dpa.allocated_page_file_id
    , PageID = dpa.allocated_page_page_id
    , PageTypeDesc = dpa.page_type_desc
FROM sys.dm_db_database_page_allocations(DB_ID(), @ObjectID, NULL, NULL, 'DETAILED') dpa

La sortie ressemble à:

╔════════╦════════╦══════════════╗
║ FileID ║ PageID ║ PageTypeDesc ║
╠════════╬════════╬══════════════╣
║ 1 ║ 1598 ║ IAM_PAGE ║
║ 3 ║ 105368 ║ DATA_PAGE ║
║ 3 ║ 105369 ║ NULL ║
║ 3 ║ 105370 ║ NULL ║
║ 3 ║ 105371 ║ NULL ║
║ 3 ║ 105372 ║ NULL ║
║ 3 ║ 105373 ║ NULL ║
║ 3 ║ 105374 ║ NULL ║
║ 3 ║ 105375 ║ NULL ║
╚════════╩════════╩══════════════╝

Ce qui est logique, à part la page ROW_OVERFLOW_DATA manquante. Nous avons une seule page de carte d'allocation d'index et une pleine étendue de pages de données de 8 Ko, avec une seule de ces pages réellement allouée.

De même, si j'utilise la sys.fn_PhysLocCrackerfonction non documentée pour afficher la page où chaque ligne existe, comme dans:

SELECT *
FROM dbo.t
CROSS APPLY sys.fn_PhysLocCracker(%%PHYSLOC%%)

Je ne vois que la DATA_PAGEliste:

╔════════╦═════════════╦═════════════════════╦════ ═════╦═════════╦═════════╗
║ rownum ║ on_row_data ║ off_row_data ║ file_id ║ page_id ║ slot_id ║
╠════════╬═════════════╬═════════════════════╬════ ═════╬═════════╬═════════╣
║ 1 ║ on_row_data ║ AAAAAAAAAAAAAAAAAAA ║ 3 ║ 105368 ║ 0 ║
╚════════╩═════════════╩═════════════════════╩════ ═════╩═════════╩═════════╝

De même, si j'utilise, DBCC IND(database, table, index)je ne vois que les deux pages listées:

DBCC IND (tempdb, t, 1);

Production:

╔═════════╦═════════╦════════╦════════╦═══════════ ═╦═════════╦═════════════════╦════════════════════ ═╦════════════════╦══════════╦════════════╦═══════ ══════╦═════════════╦═════════════╦═════════════╦═ ═╗
║ PageFID ║ PagePID ║ IAMFID ║ IAMPID ║ ObjectID ║ IndexID ║ PartitionNumber ║ PartitionID ║ iam_chain_type ║ PageType ║ IndexLevel ║ NextPageFID ║ NextPagePID ║ PrevPageFID ║ PrevPagePID ║ ║ ║
╠═════════╬═════════╬════════╬════════╬═══════════ ═╬═════════╬═════════════════╬════════════════════ ═╬════════════════╬══════════╬════════════╬═══════ ══════╬═════════════╬═════════════╬═════════════╬═ ═╣
║ 1 ║ 1598 ║ NULL ║ NULL ║ 2069582411 ║ 1 ║ 1 ║ 6989586877272752128 ║ Données en ligne ║ 10 ║ NULL ║ 0 ║ 0 ║ 0 ║ 0 ║ ║
║ 3 ║ 105368 ║ 1 ║ 1598 ║ 2069582411 ║ 1 ║ 1 ║ 6989586877272752128 ║ Données en ligne ║ 1 ║ 0 ║ 0 ║ 0 ║ 0 ║ 0 ║ ║
╚═════════╩═════════╩════════╩════════╩═══════════ ═╩═════════╩═════════════════╩════════════════════ ═╩════════════════╩══════════╩════════════╩═══════ ══════╩═════════════╩═════════════╩═════════════╩═ ═╝

Si je regarde le contenu des pages réelles, en utilisant DBCC PAGE, il semble que je encore ne vois rien sur quelle page contient la ROW_OVERFLOW_DATA - Je suis sûr qu'il doit être là, je ne sais probablement pas quoi regarder:

DBCC PAGE (tempdb, 3, 105368 , 3) WITH TABLERESULTS;

Les résultats sont trop gros pour tenir ici, si j'inclus les lignes de vidage de la mémoire, mais voici la sortie de l'en-tête:

╔══════════════╦════════════════════════════════╦═ ══════════════════════════════╦═══════════════════ ════════════╗
║ ParentObject ║ Objet ║ Champ ║ VALEUR ║
╠══════════════╬════════════════════════════════╬═ ══════════════════════════════╬═══════════════════ ════════════╣
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bpage ║ 0x000002431A8A2000 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bhash ║ 0x0000000000000000 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bpageno ║ (3: 105368) ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bdbid ║ 2 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ breferences ║ 0 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bcputicks ║ 0 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bsampleCount ║ 0 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bUse1 ║ 63172 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bstat ║ 0x10b ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ blog ║ 0x212121cc ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bnext ║ 0x0000000000000000 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bDirtyContext ║ 0x000002435DA77160 ║
║ TAMPON: ║ BUF @ 0x000002437E86D5C0 ║ bstat2 ║ 0x0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_pageId ║ (3: 105368) ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_headerVersion ║ 1 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_type ║ 1 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_typeFlagBits ║ 0x0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_level ║ 0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_flagBits ║ 0xc000 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_objId (AllocUnitId.idObj) ║ 3920762 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_indexId (AllocUnitId.idInd) ║ 512 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ Métadonnées: AllocUnitId ║ 144115445026914304 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ Métadonnées: PartitionId ║ 6989586877272752128 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ Métadonnées: IndexId ║ 1 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ Métadonnées: ObjectId ║ 2069582411 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_prevPage ║ (0: 0) ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_nextPage ║ (0: 0) ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ pminlen ║ 8 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_slotCnt ║ 1 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_freeCnt ║ 66 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_freeData ║ 8124 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_reservedCnt ║ 0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_lsn ║ (36: 47578: 1) ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_xactReserved ║ 0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_xdesId ║ (0: 0) ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_ghostRecCnt ║ 0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ m_tornBits ║ 0 ║
║ EN-TÊTE DE PAGE: ║ Page @ 0x000002431A8A2000 ║ ID de fragment de base de données ║ 1 ║
║ EN-TÊTE DE PAGE: ║ Statut d'allocation ║ GAM (3: 2) ║ ATTRIBUÉ ║
║ EN-TÊTE DE PAGE: ║ Statut d'allocation ║ SGAM (3: 3) ║ NON ATTRIBUÉ ║
║ EN-TÊTE DE PAGE: ║ Statut d'allocation ║ PFS (3: 105144) ║ 0x40 ALLOCÉ 0_PCT_FULL ║
║ EN-TÊTE DE PAGE: ║ Statut d'allocation ║ DIFF (3: 6) ║ NON MODIFIÉ ║
║ EN-TÊTE DE PAGE: ║ Statut d'allocation ║ ML (3: 7) ║ NON MIN_LOGGED ║
║ EN-TÊTE DE PAGE: ║ Slot 0 Offset 0x60 Longueur 8028 ║ Type d'enregistrement ║ PRIMARY_RECORD ║
║ EN-TÊTE DE PAGE: ║ Décalage de l'emplacement 0 0x60 Longueur 8028 ║ Attributs d'enregistrement ║ NULL_BITMAP VARIABLE_COLUMNS ║
║ EN-TÊTE DE PAGE: ║ Décalage de l'emplacement 0 0x60 Longueur 8028 ║ Taille d'enregistrement ║ 8028 ║
╚══════════════╩════════════════════════════════╩═ ══════════════════════════════╩═══════════════════ ════════════╝

Réponses:


10

Votre démo est frappée par une limitation de REPLICATE :

Si expression_chaîne n'est pas de type varchar (max) ou nvarchar (max), REPLICATE tronque la valeur de retour à 8 000 octets. Pour renvoyer des valeurs supérieures à 8 000 octets, expression_chaîne doit être explicitement convertie en type de données de grande valeur approprié.

Si je fais ça:

INSERT INTO dbo.t (off_row_data) VALUES (REPLICATE(CAST('A' as varchar(max)), 20000));

Et puis exécutez votre requête DMV d'en haut contre dm_db_database_page_allocations, j'obtiens des pages avec un PageTypeDesc de TEXT_MIX_PAGE.

Je peux ensuite exécuter DBCC PAGE avec l'indicateur de trace 3604 activé afin de voir les détails de cette page hors ligne:

DBCC TRACEON (3604);
GO
DBCC PAGE (TestDB, 1, 20696 , 3) -- your page will be different :)

La sortie est grande, mais vers le début, vous verrez:

Blob row at: Page (1:20696) Slot 0 Length: 3934 Type: 3 (DATA)

Et puis, vous savez, un tas de A.


4
Ce ne serait pas bien, cependant, s'il y avait un avertissement de troncature, ou quelque chose.
Max Vernon
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.