《Microsoft Sql server 2008 Internals》读书笔记订阅地址:
http://www.cnblogs.com/downmoon/category/230397.html/rss
《Microsoft Sql server 2008 Internals》索引目录:
《Microsoft Sql server 2008 Internal》读书笔记--目录索引
前面我们学习了数据页 的存储结构以及如何检查一个data page。那么如何查询一个物理页呢?
记得在上篇文章时,我们介绍了了一个未公开的DBCC PAGE命令。该命令前需要知道页的具体参数,如
--查询testdb数据库的第一个文件的第157页的数据页
--DBCC PAGE (testdb,1,157,1);
那么,如何查询第一页(first_page)的值呢?我们来看一个例子:假定我们创建一个表Fixed,语句如下:
CREATE
TABLE
Fixed
(
Col1
char
(
5
)
NOT
NULL
,
Col2
int
NOT
NULL
,
Col3
char
(
3
)
NULL
,
Col4
char
(
6
)
NOT
NULL
);
INSERT
Fixed
VALUES
(
'
ABCDE
'
,
123
,
NULL
,
'
CCCC
'
);
用下列语句,可以查询Fixed表的first_page的值。
SELECT
object_name
(
object_id
)
AS
name,
rows, type_desc
as
page_type_desc,
total_pages
AS
pages, first_page
FROM
sys.partitions p
JOIN
sys.system_internals_allocation_units a
ON
p.partition_id
=
a.container_id
WHERE
object_id
=
object_id
(
'
dbo.Fixed
'
);
结果为:
name rows page_type_desc pages first_page
Fixed 1 IN_ROW_DATA 2 0xEE0000000100
我们将这个十六进制结果转化一下,00 10 00 00 00 EE。
前两个group代表一个2字节的文件数。这里是0x0001,页数是00EE,十进制是。可以通过一个function来转换。
CREATE
FUNCTION
convert_page_nums (
@page_num
binary
(
6
))
RETURNS
varchar
(
11
)
AS
BEGIN
RETURN
(
convert
(
varchar
(
2
), (
convert
(
int
,
substring
(
@page_num
,
6
,
1
))
*
power
(
2
,
8
))
+
(
convert
(
int
,
substring
(
@page_num
,
5
,
1
))))
+
'
:
'
+
convert
(
varchar
(
11
),
(
convert
(
int
,
substring
(
@page_num
,
4
,
1
))
*
power
(
2
,
24
))
+
(
convert
(
int
,
substring
(
@page_num
,
3
,
1
))
*
power
(
2
,
16
))
+
(
convert
(
int
,
substring
(
@page_num
,
2
,
1
))
*
power
(
2
,
8
))
+
(
convert
(
int
,
substring
(
@page_num
,
1
,
1
)))) )
END
;
SELECT
dbo.convert_page_nums(
0xEE0000000100
);
结果为1:238
警告:first_page列并不一直是指向表的第一页。毕竟这是一个未公开的命令。
第二种获取页实际数字的方式是使用另外一个未公开的命令DBCC IND。例如:
DBCC
IND(testdb, fixed,
-
1
);
得到如下类似结果:
PageFID PagePID IAMFID IAMPID ObjectID IndexID PartitionNumber PartitionID iam_chain_type PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID
1
238
1
239
1029578706
0
1
72057594041925632
In-row data
1
0
0
0
0
0
第三种方式是使用一个未公开的function:sys.fn_PhysLocFormatter
SELECT
sys.fn_PhysLocFormatter (
%%
physloc
%%
)
AS
RID,
*
FROM
Fixed;
结果:
RID Col1 Col2 Col3 Col4
(1:60928:0) ABCDE 123 NULL CCCC
请注意这个结果有所不同。
下面将分别介绍五种类型的存储方式:
一、固定长度的行;二、可变长度的行;三、Null和可变长度列;四、时间和日期数据;五、SQL_variant 数据
首先,我们来看第一种:固定长度的行的存储。
我们以前面创建的Fixed表为例:
一旦表被创建,我们可以从目录视图中查看到相关列的信息;
SELECT
object_id
, type_desc,
indexproperty
(
object_id
, name,
'
minlen
'
)
as
min_row_len
FROM
sys.indexes
where
object_id
=
object_id
(
'
Fixed
'
);
SELECT
column_id, name, system_type_id, max_length
as
max_col_len
FROM
sys.columns
WHERE
object_id
=
object_id
(
'
Fixed
'
);
结果:
object_id type_desc min_row_len
1029578706
HEAP
22
column_id name system_type_id max_col_len
1
Col1
175
5
2
Col2
56
4
3
Col3
175
3
4
Col4
175
6
注意:sysindexes目录视图包含列minlen和xmaxlen,存储了行的最小和最大长度。在Sql Server2008中,这些值在任何视图中是不可用的,除非你通过一个未公开的function:indexproperty读取它。对于一个只包含固定长度的列的表来说,indexproperty函数通过传入的minlen返回值等于列长度的总和(从sys.columns.max_length)加上4个字节。它不包含列数目的两个字节和用于null位图的字节。
通过以下语句可以查看列的偏移量:
SELECT
c.name
AS
column_name, column_id, max_inrow_length,
pc.system_type_id, leaf_offset
FROM
sys.system_internals_partition_columns pc
JOIN
sys.partitions p
ON
p.partition_id
=
pc.partition_id
JOIN
sys.columns c
ON
column_id
=
partition_column_id
AND
c.
object_id
=
p.
object_id
WHERE
p.
object_id
=
object_id
(
'
fixed
'
);
Col1
1
5
175
4
Col2
2
4
56
9
Col3
3
3
175
13
Col4
4
6
175
16
对了,如何显示Buffer数据,请参看上篇内容
简要说明:
1、第一个字节:状态位A是0x10显示bit4打开,bit5未打开。我们得知该行没有可变长度列。
2、第二个字节未使用。
3、第三和第四字节是0x16等于22,显示了固定长度的列长度之和。
4、各列的偏移量分别为4,9,13,16。
5、第22字节处是0400,表明列数为4
6、null bitmap未使用。
说实话,这节和下节是本书第二难理解的内容。最难理解的内容要数第七章了。呵呵。邀月确实有点半生不熟。共同学习是我的目的。