您的位置:首页 > 其它

翻译如何通过页ID知道表名

2014-10-11 10:58 148 查看
翻译如何通过页ID知道表名

原文:Finding a table name from a page ID

原文地址:http://www.sqlskills.com/blogs/paul/finding-table-name-page-id/

译者:如果在一些特殊情况下只知道页ID,如何知道这是哪个表的页呢?本文主要解决这个问题。

正文:

想象一下某个早晨,你回去工作发现在夜间有一些新行插入到msdb.dbo.suspect_pages表中。通常你做的第一件事是运行DBCC CHECKDB,但是如果你的数据库有几个TB,这样可能得运行几个小时才能知道问题出在哪里——哪个表丢失了数据。但是你想到尽快找到哪个表,这样你可以选择灾难恢复方案。

另一个情形是:你在找出性能差的查询——运行我的脚本,用sys.dm_os_waiting_tasks来查看当前等待的线程,你看到许多PAGELATCH_EX等待,你需要通过sys.dm_os_waiting_tasks的resource_description列中的页ID知道哪个表。

回到第一种情形,通过suspect_pages表得到数据比较简单:

SELECT * FROM [msdb].[dbo].[suspect_pages];

GO

database_id file_id page_id event_type error_count last_update_date

----------- ----------- -------------------- ----------- ----------- -----------------------

6 1 295 2 2 2014-09-25 01:18:22.910

要发现表名,首先需要使用DBCC PAGE。DBCC PAGE语法如下:

dbcc page ( {'dbname' | dbid}, filenum, pagenum [, printopt={0|1|2|3} ])
你可以只使用PRINT OPTION 0,这样只是显示表头。你同时必须使用TRACE FLAG 3604来获得DBCC PAGE的输出——这相当安全。你们使用suspect_pages的输出,DBCC PAGE的返回如下:

DBCC TRACEON (3604);

DBCC PAGE (6, 1, 295, 0);

DBCC TRACEOFF (3604);

GO

PAGE: (1:295)

BUFFER:

BUF @0x00000004FD8C7980

bpage = 0x00000004A2D14000 bhash = 0x0000000000000000 bpageno = (1:295)

bdbid = 6 breferences = 0 bcputicks = 0

bsampleCount = 0 bUse1 = 55116 bstat = 0x809

blog = 0x15ab215a bnext = 0x0000000000000000

PAGE HEADER:

Page @0x00000004A2D14000

m_pageId = (1:295) m_headerVersion = 17 m_type = 17

m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8200

m_objId (AllocUnitId.idObj) = 84 m_indexId (AllocUnitId.idInd) = 256

Metadata: AllocUnitId = 72057594043432960

Metadata: PartitionId = 72057594039042048 Metadata: IndexId = 0

Metadata: ObjectId = 245575913 m_prevPage = (0:0) m_nextPage = (0:0)

pminlen = 8008 m_slotCnt = 1 m_freeCnt = 83

m_freeData = 8107 m_reservedCnt = 0 m_lsn = (35:200:9)

m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0

m_tornBits = 1093512791 DB Frag ID = 1

Allocation Status

GAM (1:2) = ALLOCATED SGAM (1:3) = ALLOCATED

PFS (1:1) = 0x64 MIXED_EXT ALLOCATED 100_PCT_FULL DIFF (1:6) = CHANGED

ML (1:7) = NOT MIN_LOGGED

我们感兴趣的是从metadata开始的部分。这些字段并不存放在数据本身之中。当初为SQL SERVER 2005重写DBCC PAGE时,我加入了metadata输出部分——这样比较容易找到该页所属的对象ID和索引ID(就像在SQL SERVER 7.0和2000中m_objId和m_indexId一样)。

Metadata:objectId就是我们想要的。如果你看到它是99,那么请打住——因为这意味着损坏页是分配系统的一部分——并不是一个表的页,你需要等待DBCC CHECKDB结束来知道哪个区(extent)坏了。

如果你看到ObjectId是0,这意味着没有发现metadata数据。这可能是以下原因:

1) 自从损坏被记录后,表所包含的该页已经被删除。

2) 系统目录由于某种原因损坏。

3) 页损坏,所以导致不正确的值用来查找metadata(当然查不到了)。

不管上面的什么哪一种情况,你必须等待DBCC CHECKDB结束来知道哪个区(extent)发生了破坏。

如果ObjectId不是0或者99,你可以将该值放到OBJECT_NAME函数中来获得表名:

SELECT OBJECT_NAME (245575913);

GO

----------------------------------------------------------------------------------------

NULL

如果你得到上面的结果,那么可能有两种原因:

你使用了错误的数据库上线文

数据库的元数据(metadata)已经被损坏,所以你只好等待DBCC CHECKDB结束。

根据我的经验,很有可能使第一种情况。你可以在suspect_pages输出的database_id,然后将它带入到DB_NAME得到数据库名称,在正确的数据库上下文中,再试一次:

USE [company];

GO

SELECT OBJECT_NAME (245575913);

GO

--------------------------------------------------------------------------------------------------------------------------------

CustomerNames

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐