列出特定表的ROW_OVERFLOW_DATA页


11

我正在尝试获取具有ROW_OVERFLOW_DATA行的表的页面列表。我可以从未记录的DMV中获得分配页面的列表sys.db_db_database_page_allocations,但是,该DMV的输出中似乎没有列出ROW_OVERFLOW_DATA页面。还有我无法找到的其他DMV吗?

最小,完整和(希望!)可验证的示例:

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

输出如下:

╔════════╦════════╦══════════════╗
║文件ID║PageID║PageTypeDesc║
╠════════╬════════╬══════════════╣
║1║1598║IAM_PAGE║
║3║105368║DATA_PAGE║
║3║105369║空║
║3║105370║空║
║3║105371║空║
║3║105372║空║
║3║105373║空║
║3║105374║空║
║3║105375║空║
╚════════牛皮════════牛皮══════════════╝

除了缺少的ROW_OVERFLOW_DATA页面之外,这很有道理。我们只有一个索引分配映射页面,以及一个全范围的8KB数据页面,仅实际分配了其中一个页面。

同样,如果我使用未记录的sys.fn_PhysLocCracker功能来显示每一行所在的页面,如下所示:

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

我只看到DATA_PAGE列出的内容:

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

同样,如果我使用,DBCC IND(database, table, index)我只会看到列出的两个页面:

DBCC IND (tempdb, t, 1);

输出:

╔═════════╦═════════╦════════╦════════╦═══════════ ═╦═════════╦═════════════════╦════════════════════ ═╦════════════════╦══════════╦════════════╦═══════ ══════╦═════════════╦═════════════╦═════════════╦═ ═╗
F 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║行内数据║10║NULL║0║0║0║0║0║
║3║105368║1║1598║2069582411║1║1║6989586877272752128║行内数据║1║0║0║0║0║0║0║
╚═════════牛皮═════════牛皮════════牛皮════════牛皮═══════════ ═牛皮═════════牛皮═════════════════牛皮═════════════════ ═牛皮════════════════牛皮══════════牛皮══════════牛皮═══════ ══════牛皮═════════════牛皮═════════════牛皮═════════════牛皮═ ═╝

如果我使用来查看页面的实际内容,DBCC PAGE似乎仍然看不到哪个页面包含ROW_OVERFLOW_DATA的任何内容-我确定它必须在那里,我可能只是不知道要看什么:

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

如果我包括内存转储行,结果太大了,不适合这里,但这是标头输出:

╔══════════════╦════════════════════════════════╦═ ══════════════════════════════╦═══════════════════ ════════════╗
║父对象║对象║字段║值║
╠══════════════╬════════════════════════════════╬═ ══════════════════════════════╬═══════════════════ ════════════╣
║缓冲区:║BUF @ 0x000002437E86D5C0║bpage║0x000002431A8A2000║
║缓冲区:║BUF @ 0x000002437E86D5C0║bhash║0x0000000000000000║
║缓冲区:║BUF @ 0x000002437E86D5C0║bpageno║(3:105368)║
║BUFFER:║BUF @ 0x000002437E86D5C0║bdbid║2║
║BUFFER:║BUF @ 0x000002437E86D5C0║引用║0║
║缓冲区:║BUF @ 0x000002437E86D5C0║bcputicks║0║
║缓冲区:║BUF @ 0x000002437E86D5C0║bsampleCount║0║
║缓冲区:║BUF @ 0x000002437E86D5C0║bUse1║63172║
║缓冲区:║BUF @ 0x000002437E86D5C0║bstat║0x10b║
║缓冲区:║BUF @ 0x000002437E86D5C0║博客║0x212121cc║
║缓冲区:║BUF @ 0x000002437E86D5C0║bnext║0x0000000000000000║
║缓冲区:║BUF @ 0x000002437E86D5C0║bDirtyContext║0x000002435DA77160║
║缓冲区:║BUF @ 0x000002437E86D5C0║bstat2║0x0║
║页头:║页@ 0x000002431A8A2000║m_pageId║(3:105368)║
║页头:║页@ 0x000002431A8A2000║m_headerVersion║1║
║页头:║页@ 0x000002431A8A2000║m_type║1║
║页头:║页@ 0x000002431A8A2000║m_typeFlagBits║0x0║
║页头:║页@ 0x000002431A8A2000║m_level║0║
║页头:║页@ 0x000002431A8A2000║m_flagBits║0xc000║
║页头:║页@ 0x000002431A8A2000║m_objId(AllocUnitId.idObj)║3920762║
║页头:║页@ 0x000002431A8A2000║m_indexId(AllocUnitId.idInd)║512║
║页头:║页@ 0x000002431A8A2000║元数据:AllocUnitId║144115445026914304
║页头:║页@ 0x000002431A8A2000║元数据:PartitionId║6989586877272752128║
║页头:║页@ 0x000002431A8A2000║元数据:IndexId║1║
║页头:║页@ 0x000002431A8A2000║元数据:ObjectId║2069582411║
║页头:║页@ 0x000002431A8A2000║m_prevPage║(0:0)║
║页头:║页@ 0x000002431A8A2000║m_nextPage║(0:0)║
║页面标题:║页面@ 0x000002431A8A2000║pminlen║8║
║页头:║页@ 0x000002431A8A2000║m_slotCnt║1║
║页头:║页@ 0x000002431A8A2000║m_freeCnt║66║
║页头:║页@ 0x000002431A8A2000║m_freeData║8124║
║页头:║页@ 0x000002431A8A2000║m_reservedCnt║0║
║页头:║页@ 0x000002431A8A2000║m_lsn║(36:47578:1)║
║页头:║页@ 0x000002431A8A2000║m_xactReserved║0║
║页头:║页@ 0x000002431A8A2000║m_xdesId║(0:0)║
║页头:║页@ 0x000002431A8A2000║m_ghostRecCnt║0║
║页头:║页@ 0x000002431A8A2000║m_tornBits║0║
║页头:║页@ 0x000002431A8A2000║DB Frag ID║1║
║页面标题:║分配状态║GAM(3:2)║已分配║
║页头:║分配状态║SGAM(3:3)║未分配║
║页头:║分配状态║PFS(3:105144)║0x40分配0_PCT_FULL║
║页头:║分配状态║DIFF(3:6)║未更改║
║页头:║分配状态║ML(3:7)║NOT MIN_LOGGED║
║页头:║插槽0偏移量0x60长度8028║记录类型║PRIMARY_RECORD║
║页头:║插槽0偏移量0x60长度8028║记录属性║NULL_BITMAP VARIABLE_COLUMNS║
║页面标题:║插槽0偏移0x60长度8028║记录大小║8028║
╚══════════════牛皮════════════════════════════════牛皮═ ══════════════════════════════牛皮═══════════════════ ════════════╝

Answers:


10

您的演示受到REPLICATE限制

如果string_expression不是varchar(max)或nvarchar(max)类型,则REPLICATE将返回值截断为8,000个字节。要返回大于8,000个字节的值,必须将string_expression显式转换为适当的大值数据类型。

如果我这样做:

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

然后针对dm_db_database_page_allocations从上方运行您的DMV查询,我得到的页面类型为 TEXT_MIX_PAGE

然后,我可以运行启用了跟踪标志3604的DBCC PAGE,以查看该行外页面的详细信息:

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

输出很大,但是在开始时会看到:

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

然后,您知道,一堆A。


4
但是,如果有截断警告之类的东西,那会不会很好。
Max Vernon
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.