查看对象物理存储位置

简介:

So lately I've been geeking out on SQL internals. My most recent find involves a couple of undocumented toys, DBCC Pageand sys.system_internals_allocation_units.

DBCC Page will actually display the contents of a page. I found a blog post by Paul Randal, back when he still worked for Microsoft, describing the DBCC Page command. Here's a summary:

dbcc page ( {'dbname' | dbid}, filenum, pagenum [, printopt={0|1|2|3} ])

The filenum and pagenum parameters are taken from the page IDs that come from various system tables and appear in DBCC or other system error messages. A page ID of, say, (1:354) has filenum = 1 and pagenum = 354.

The printopt parameter has the following meanings:

* 0 - print just the page header
* 1 - page header plus per-row hex dumps and a dump of the page slot array (unless its a page that doesn't have one, like allocation bitmaps)
* 2 - page header plus whole page hex dump
* 3 - page header plus detailed per-row interpretation

The per-row interpretation work for all page types, including allocation bitmaps.

We'll come back to actually viewing a page in just a minute. Now that we know we can view page contents, how do we find out which pages contain the data we want to look at? This is where sys.system_internals_allocation_units can help. The sys.system_internals_allocation_units DMV is just like sys.allocation_units, except it has a few additional columns of interest: [first_page], [root_page], and [first_iam_page]. The query below will return the filenum and pagenum values, for use in the DBCC Page command, for a specific table.

Select Object_Name(p.object_id) As 'tableName'
    , i.name As 'indexName'
    , p.partition_number
    , au.type_desc
    , Convert (varchar(6),
      Convert (int, SubString (au.first_page, 6, 1) +
         SubString (au.first_page, 5, 1))) +
   ':' + Convert (varchar(20),
      Convert (int, SubString (au.first_page, 4, 1) +
         SubString (au.first_page, 3, 1) +
         SubString (au.first_page, 2, 1) +
         SubString (au.first_page, 1, 1))) As 'firstPage'
    , Convert (varchar(6),
      Convert (int, SubString (au.root_page, 6, 1) +
         SubString (au.root_page, 5, 1))) +
   ':' + Convert (varchar(20),
      Convert (int, SubString (au.root_page, 4, 1) +
         SubString (au.root_page, 3, 1) +
         SubString (au.root_page, 2, 1) +
         SubString (au.root_page, 1, 1))) As 'rootPage'
    , Convert (varchar(6),
      Convert (int, SubString (au.first_iam_page, 6, 1) +
         SubString (au.first_iam_page, 5, 1))) +
   ':' + Convert (varchar(20),
      Convert (int, SubString (au.first_iam_page, 4, 1) +
         SubString (au.first_iam_page, 3, 1) +
         SubString (au.first_iam_page, 2, 1) +
         SubString (au.first_iam_page, 1, 1))) As 'firstIAM_page'
From sys.indexes As i
Join sys.partitions As p
    On i.object_id = p.object_id
    And i.index_id = p.index_id
Join sys.system_internals_allocation_units As au
    On p.hobt_id = au.container_id
Where Object_Name(p.object_id) = 'ProductReview'
Order By tableName;

Note: the conversion code was borrowed from one of Kimberley Tripp's posts, see the References section for the link.

Running the preceding query in the AdventureWorks database will produce the following:

tableName  indexName                           partition_number type_desc    firstPage  rootPage  firstIAM_page
---------- ----------------------------------- ---------------- ------------ ---------- --------- --------------
ProductRev PK_ProductReview_ProductReviewID    1                IN_ROW_DATA  1:770      1:773     1:771
ProductRev IX_ProductReview_ProductID_Name     1                IN_ROW_DATA  1:911      1:914     1:912

Great, now we have a starting place! Let's now take DBCC Page out for a spin and see what it can do. I'm going to use the [firstPage] value for the IX_ProductReview_ProductID_Name index. Remember, the value preceding the colon (:) is your file number, and the value after it is your page number.

DBCC TraceOn (3604);
DBCC Page (AdventureWorks, 1, 911, 3);
DBCC TraceOff (3604);

You should get back something like the following. (Note: for brevity's sake, I'm only displaying part of the results)

Allocation Status
 
GAM (1:2) = ALLOCATED                SGAM (1:3) = NOT ALLOCATED           
PFS (1:1) = 0x60 MIXED_EXT ALLOCATED   0_PCT_FULL                         DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED            
FileId PageId      Row    Level  ProductID (key) ReviewerName (key)                                 ProductReviewID (key) Comments
------ ----------- ------ ------ --------------- -------------------------------------------------- --------------------- -------------------------------------------------------------------------
1      911         0      0      709             John Smith                                         1                     I can't believe I'm singing the praises of a pair of socks, but...(79025483b74e)

Let's take a moment to consider why we're seeing this. You'll notice there's 3 columns with (key) next to the name: [ProductID], [ReviewerName], and [ProductReviewID]. There's one column without (key): [Comments]. This is exactly what I was expecting to see. Why? If you take a look at the details of IX_ProductReview_ProductID_Name, you'll notice it's a non-clustered index on only [ProductID, ReviewerName], with an included column, [Comments]. You'll also notice the clustered index on Production.ProductReview is [ProductReviewID]. Remember, the composition of a non-clustered index includes the clustered index value as a sort of row pointer.

Not sure how to view the details of an index, like included columns? Check out my Index Interrogation Script.

I was interested in the ordering of the data. I wasn't sure whether I'd find [ProductReviewID] first or last. But after looking at several of these examples, I've always found the clustered index to be nestled behind the non-clustered index columns and before the included columns (as exampled above).

That's all I have for now. Try it out, play with the different printopt values, look at different types of pages, and have fun. Oh, and if anyone has a link to a blog post or a book that explains each of the items in the page header, I'd greatly appreciate it. :)

Happy Digging!

Michelle



    本文转自 Fanr_Zh 博客园博客,原文链接:http://www.cnblogs.com/Amaranthus/archive/2011/08/18/2144249.html,如需转载请自行联系原作者





相关文章
|
4天前
|
存储 程序员 C语言
动态存储方式与静态存储方式
在编程中,数据的存储方式对于程序的性能、内存使用以及代码的可维护性都有着至关重要的影响。其中,动态存储方式和静态存储方式是两种常见的数据存储方式。本文将探讨这两种存储方式的区别、应用场景,并附上相应的代码示例。
33 1
|
4天前
|
存储 数据中心 云计算
逻辑存储和物理存储各代表什么?区别是什么?
逻辑存储和物理存储各代表什么?区别是什么?
|
7月前
|
存储 算法 调度
分页储存管理.分段储存管理.虚拟储存管理
分页储存管理和分段储存管理是操作系统中常用的两种内存管理方式。 1. 分页储存管理: - 基本原理:将物理内存和逻辑内存划分为固定大小的页面和页面框,使得逻辑地址空间和物理地址空间可以对应起来。进程的逻辑地址空间被划分为多个固定大小的页面,每个页面与一个物理内存页面框对应。通过页表将逻辑地址映射到物理地址,实现地址转换。 - 优点:简单、灵活,能够提供较大的逻辑地址空间,适用于多道程序设计和虚拟内存管理。 - 缺点:存在内部碎片,会造成一定的存储空间浪费。 2. 分段储存管理: - 基本原理:将进程的逻辑地址空间划分为若干个逻辑段,每个逻辑段代表一个逻辑单位,如代码
116 0
|
9月前
|
存储 编译器 C语言
你知道数据在内存中是如何存储的嘛?(二)
你知道数据在内存中是如何存储的嘛?(二)
125 0
|
4天前
|
存储 编译器 C++
C/C++ 函数的存储位置和占用空间
C/C++ 函数的存储位置和占用空间
17 0
|
8月前
|
存储 安全 API
2.1 PE结构:文件映射进内存
PE结构是`Windows`系统下最常用的可执行文件格式,理解PE文件格式不仅可以理解操作系统的加载流程,还可以更好的理解操作系统对进程和内存相关的管理知识,在任何一款操作系统中,可执行程序在被装入内存之前都是以文件的形式存放在磁盘中的,在早期DOS操作系统中,是以COM文件的格式存储的,该文件格式限制了只能使用代码段,堆栈寻址也被限制在了64KB的段中,由于PC芯片的快速发展这种文件格式极大的制约了软件的发展。
271 0
|
9月前
|
存储 编译器 C语言
你知道数据在内存中是如何存储的嘛?(一)
你知道数据在内存中是如何存储的嘛?(一)
78 0
|
10月前
|
存储 算法 5G
【软考学习12】页式存储、段式存储、段页式存储和物理逻辑地址转换
【软考学习12】页式存储、段式存储、段页式存储和物理逻辑地址转换
1070 0
|
存储 Android开发 内存技术
安卓开发之在internal存储区中存取文件和外部存储区存放文件
安卓开发之在internal存储区中存取文件和外部存储区存放文件,所有的Android设备有两个物理存储区域:"internal" 和"external"。这些名字来自于Android早期,那时大部分设备提供内置的非易失内存(internal存储),再加一个可移除的存储媒介,如SD卡(external存储)。
86 1
安卓开发之在internal存储区中存取文件和外部存储区存放文件