列出特定表的 ROW_OVERFLOW_DATA 页

Han*_*non 11 sql-server database-internals

我正在尝试获取具有 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
Run Code Online (Sandbox Code Playgroud)

输出看起来像:

????????????????????????????????????
? 文件 ID ? 页面 ID ? 页面类型描述 ?
????????????????????????????????????
? 1 ? 1598?IAM_PAGE ?
? 3 ? 105368?数据页?
? 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%%)
Run Code Online (Sandbox Code Playgroud)

我只看到DATA_PAGE列出的:

?????????????????????????????????????????????????????? ??????????????????????????????
? 行数?on_row_data ? off_row_data ? 文件 ID ? 页码?slot_id ?
?????????????????????????????????????????????????????? ??????????????????????????????
? 1 ? on_row_data ? AAAAAAAAAAAAAAAAAAA ?3 ? 105368?0 ?
?????????????????????????????????????????????????????? ??????????????????????????????

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

DBCC IND (tempdb, t, 1);
Run Code Online (Sandbox Code Playgroud)

输出:

?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ??
? 页面FID ? 页面PID ? IAMFID ? IAMPID ? 对象 ID ? 索引 ID ? 分区号?分区 ID ? iam_chain_type ? 页面类型?索引级别?NextPageFID ? NextPagePID ? 上一页FID ? 上一页PID ? ?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ??
? 1 ? 1598?空值 ?空值 ?2069582411 ? 1 ? 1 ? 6989586877272752128 ? 行内数据 ? 10 ? 空值 ?0 ? 0 ? 0 ? 0 ? ?
? 3 ? 105368?1 ? 1598?2069582411 ? 1 ? 1 ? 6989586877272752128 ? 行内数据 ? 1 ? 0 ? 0 ? 0 ? 0 ? 0 ? ?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ??

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

DBCC PAGE (tempdb, 3, 105368 , 3) WITH TABLERESULTS;
Run Code Online (Sandbox Code Playgroud)

如果我包含内存转储行,结果太大而无法放在这里,但这是标题输出:

?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????
? 父对象 ? 目的 ?场地 ?价值 ?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????
? 缓冲: ?BUF @0x000002437E86D5C0 ? 页面?0x000002431A8A2000 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 嘘?0x0000000000000000 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? bpageno ? (3:105368) ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? bdbid ? 2 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 偏好?0 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? bcputicks ? 0 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 样本计数?0 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? b 使用 1 ? 63172?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 统计数据?0x10b ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 博客 ?0x212121cc ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? 下一个?0x0000000000000000 ?
? 缓冲: ?BUF @0x000002437E86D5C0 ? bDirtyContext ? 0x000002435DA77160?
? 缓冲: ?BUF @0x000002437E86D5C0 ? bstat2 ? 0x0 ?
? 页眉: ? 页@0x000002431A8A2000?m_pageId ? (3:105368) ?
? 页眉: ? 页@0x000002431A8A2000?m_header 版本?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?数据库片段 ID ? 1 ?
? 页眉: ? 分配状态 ? 伽马 (3:2) ? 已分配?
? 页眉: ? 分配状态 ? SGAM (3:3) ? 未分配?
? 页眉: ? 分配状态 ? PFS (3:105144) ? 0x40 分配 0_PCT_FULL ?
? 页眉: ? 分配状态 ? 差异 (3:6) ? 没有改变 ?
? 页眉: ? 分配状态 ? 毫升(3:7)?不是 MIN_LOGGED 吗?
? 页眉: ? 插槽 0 偏移 0x60 长度 8028 ? 记录类型 ? PRIMARY_RECORD ?
? 页眉: ? 插槽 0 偏移 0x60 长度 8028 ? 记录属性 ? NULL_BITMAP VARIABLE_COLUMNS ?
? 页眉: ? 插槽 0 偏移 0x60 长度 8028 ? 记录大小?8028?
?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ????????????

Jos*_*ell 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));
Run Code Online (Sandbox Code Playgroud)

然后从上面针对 dm_db_database_page_allocations 运行您的 DMV 查询,我得到 PageTypeDesc 为TEXT_MIX_PAGE.

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

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

输出很大,但在开始附近你会看到:

Blob row at: Page (1:20696) Slot 0 Length: 3934 Type: 3 (DATA)
Run Code Online (Sandbox Code Playgroud)

然后,你知道,一堆A。

  • 不过,如果有截断警告之类的,那岂不是很好。 (4认同)