转贴
:
www.windbi.com
数据库中表的存储是以page为单位的,怎么查看一个表的数据页结构呢?SQLServer2000/2005 提供了一个读取数据页结构的命令 DBCC Page 。该命令为非文档化的命令,具体如下:
DBCC Page ({dbid|dbname},filenum,pagenum[,printopt])
具体参数描述如下:
dbid 包含页面的数据库 ID
dbname 包含页面的数据库的名称
filenum 包含页面的文件编号
pagenum 文件内的页面
printopt 可选的输出选项;选用其中一个值:
0: 默认值,输出缓冲区的标题和页面标题
1: 输出缓冲区的标题、页面标题 ( 分别输出每一行 ) ,以及行偏移量表
2: 输出缓冲区的标题、页面标题 ( 整体输出页面 ) ,以及行偏移量表
3: 输出缓冲区的标题、页面标题 ( 分别输出每一行 ) ,以及行偏移量表;每一行
后跟分别列出的它的列值
要想看到这些输出的结果,还需要设置 DBCC TRACEON(3604) 。
对于表来说,它所在的 dbid 或者 dbname 很容易知道,那么它的 filenum 和 pagenum 怎么知道呢?其实这个值存在系统表 sysindexes 的列 first 中 ( 当 indid 为 0 或者 1 时, indid 为 0 表示该表是一个堆表,没有任何聚集索引, indid 为 1 表示该索引为聚集索引 ) ,列 first 的数据类型为 binary(6) ,它是以 16 进制的形式储的,需要进行转换。在 16 进制中,每两个 16 进制数字表示一个字节 ( Why? 因为每个 16 进制数字可以用 4 个二进制数字表示(每个 8 进制数字可以用 3 个二进制数字表示,天下人都知道啊),而 8 个二进制数字即 8 位为一个字节,所以两个 16 进制数字即为 1 个字节( 8 进制数字不能平分,所以出现了 16 进制哦),例如:十六进制数字 FF 就可以用二进制数字表示为 1111 1111 , 共有 8 位,而天下人都知道 1Byte=8Bit ,所以两个 16 进制数字 FF 就占用了一个字节,呵呵,是不是很绕口,绕惯了就好了,别晕就行! ) ,并且是逆序排列的。比如假设一个表的 First 的值为 0xC70000000100 ,怎么转换呢?因为它是逆序排列的,并且每两个表示一个字节,所以每次都将剩下 first 值的最后两位移到转换后数据的最后,具体转换步骤如下:
步骤 此时的 first 值 转换后的数据
第 0 步 0xC70000000100
第 1 步 0xC700000001 00
第 2 步 0xC7000000 0001
第 3 步 0xC70000 000100
第 4 步 0xC700 00010000
第 5 步 0xC7 0001000000
第 6 步 0x 0001000000C7
此时转换完成。数据 0001000000C7 即是我们需要的数据,其中它的前 2 组数 ( 即 0001) 表示该表所在的文件编号;后 4 组 (000000C7) 表示该表所在的页码 ( 注意该数据还要转换为 10 进制的数才能具体知道是多少 ) 。
完整的代码如下 ( 将设我们要查看的是表 test 的数据页的结构 ):
-- 从 sysindexes 中取出 first 的值 ( SQL2005 中即为 sys.sysindexes ,但是同样有 first 字节,简直就是系统表都变成了相应的动态视图了,但是字段都照抄过来了 )
declare @first binary(6)
select @first = first from sysindexes where id = object_id('test') and indid in(0,1)
declare @PageNum int
select @PageNum = convert(int, substring(@first,4,1) + substring(@first,3,1) +
substring(@first,2,1) + substring(@first,1,1) )
declare @FileNum int
select @FileNum = convert(int, substring(@first,6,1) + substring(@first,5,1))
select @FileNum, @PageNum
-- 执行 DBCC Page
declare @sql varchar(1000)
select @sql = 'dbcc page (''' + db_name() + ''', ' + convert(varchar(10),@FileNum) + ', ' + convert(varchar(10),@PageNum) + ', 1)'
select @sql
dbcc traceon(3604)
exec (@sql)
执行完上面的语句,就可以查看表 test 的数据页了。怎么读懂这些输出结果呢?
数据库中表的存储是以page为单位的,怎么查看一个表的数据页结构呢?SQLServer2000/2005 提供了一个读取数据页结构的命令 DBCC Page 。该命令为非文档化的命令,具体如下:
DBCC Page ({dbid|dbname},filenum,pagenum[,printopt])
具体参数描述如下:
dbid 包含页面的数据库 ID
dbname 包含页面的数据库的名称
filenum 包含页面的文件编号
pagenum 文件内的页面
printopt 可选的输出选项;选用其中一个值:
0: 默认值,输出缓冲区的标题和页面标题
1: 输出缓冲区的标题、页面标题 ( 分别输出每一行 ) ,以及行偏移量表
2: 输出缓冲区的标题、页面标题 ( 整体输出页面 ) ,以及行偏移量表
3: 输出缓冲区的标题、页面标题 ( 分别输出每一行 ) ,以及行偏移量表;每一行
后跟分别列出的它的列值
要想看到这些输出的结果,还需要设置 DBCC TRACEON(3604) 。
对于表来说,它所在的 dbid 或者 dbname 很容易知道,那么它的 filenum 和 pagenum 怎么知道呢?其实这个值存在系统表 sysindexes 的列 first 中 ( 当 indid 为 0 或者 1 时, indid 为 0 表示该表是一个堆表,没有任何聚集索引, indid 为 1 表示该索引为聚集索引 ) ,列 first 的数据类型为 binary(6) ,它是以 16 进制的形式储的,需要进行转换。在 16 进制中,每两个 16 进制数字表示一个字节 ( Why? 因为每个 16 进制数字可以用 4 个二进制数字表示(每个 8 进制数字可以用 3 个二进制数字表示,天下人都知道啊),而 8 个二进制数字即 8 位为一个字节,所以两个 16 进制数字即为 1 个字节( 8 进制数字不能平分,所以出现了 16 进制哦),例如:十六进制数字 FF 就可以用二进制数字表示为 1111 1111 , 共有 8 位,而天下人都知道 1Byte=8Bit ,所以两个 16 进制数字 FF 就占用了一个字节,呵呵,是不是很绕口,绕惯了就好了,别晕就行! ) ,并且是逆序排列的。比如假设一个表的 First 的值为 0xC70000000100 ,怎么转换呢?因为它是逆序排列的,并且每两个表示一个字节,所以每次都将剩下 first 值的最后两位移到转换后数据的最后,具体转换步骤如下:
步骤 此时的 first 值 转换后的数据
第 0 步 0xC70000000100
第 1 步 0xC700000001 00
第 2 步 0xC7000000 0001
第 3 步 0xC70000 000100
第 4 步 0xC700 00010000
第 5 步 0xC7 0001000000
第 6 步 0x 0001000000C7
此时转换完成。数据 0001000000C7 即是我们需要的数据,其中它的前 2 组数 ( 即 0001) 表示该表所在的文件编号;后 4 组 (000000C7) 表示该表所在的页码 ( 注意该数据还要转换为 10 进制的数才能具体知道是多少 ) 。
完整的代码如下 ( 将设我们要查看的是表 test 的数据页的结构 ):
-- 从 sysindexes 中取出 first 的值 ( SQL2005 中即为 sys.sysindexes ,但是同样有 first 字节,简直就是系统表都变成了相应的动态视图了,但是字段都照抄过来了 )
declare @first binary(6)
select @first = first from sysindexes where id = object_id('test') and indid in(0,1)
declare @PageNum int
select @PageNum = convert(int, substring(@first,4,1) + substring(@first,3,1) +
substring(@first,2,1) + substring(@first,1,1) )
declare @FileNum int
select @FileNum = convert(int, substring(@first,6,1) + substring(@first,5,1))
select @FileNum, @PageNum
-- 执行 DBCC Page
declare @sql varchar(1000)
select @sql = 'dbcc page (''' + db_name() + ''', ' + convert(varchar(10),@FileNum) + ', ' + convert(varchar(10),@PageNum) + ', 1)'
select @sql
dbcc traceon(3604)
exec (@sql)
执行完上面的语句,就可以查看表 test 的数据页了。怎么读懂这些输出结果呢?
代码中有很多系统函数,比如
substring(),convert(),object_id()
等等,具体怎么使用,查看
SQL Server book online.
DBCC Page 的输出主要分为 5 个部分 : Page 、 BUFFER 、 Page Hearder 、 Data 、 OFFSET Table( 行的偏移量数组 ) 。
Page 指出该表的文件编号及页码。
Buffer 指出关于给定页面的缓冲区的信息。
Page Header 指出页面中所有标题字段的数据。
Data 指出每一行的信息。对于每一行, DBCC Page 指出行在槽中的位置,以及该行在页面中的偏移量。页面数据被分成 3 部分,左列指出的是所显示的数据在行中的字节位置。接着 4 列包含页面存储的实际数据,以 16 进制的形式显示。右列包含数据的字符表示 ( 只有字符数据是可读的 ) 。
Offset Table 指出页面末尾的行偏移量数组的内容。注意这里并不是行物理存储的顺序,而是以槽的编号的顺序来显示的,不过这里可以通过槽的编号看出它的物理存储顺序,比如槽的编号最小的为物理存储的第一行,依此类推 。
DBCC Page 的输出主要分为 5 个部分 : Page 、 BUFFER 、 Page Hearder 、 Data 、 OFFSET Table( 行的偏移量数组 ) 。
Page 指出该表的文件编号及页码。
Buffer 指出关于给定页面的缓冲区的信息。
Page Header 指出页面中所有标题字段的数据。
Data 指出每一行的信息。对于每一行, DBCC Page 指出行在槽中的位置,以及该行在页面中的偏移量。页面数据被分成 3 部分,左列指出的是所显示的数据在行中的字节位置。接着 4 列包含页面存储的实际数据,以 16 进制的形式显示。右列包含数据的字符表示 ( 只有字符数据是可读的 ) 。
Offset Table 指出页面末尾的行偏移量数组的内容。注意这里并不是行物理存储的顺序,而是以槽的编号的顺序来显示的,不过这里可以通过槽的编号看出它的物理存储顺序,比如槽的编号最小的为物理存储的第一行,依此类推 。
Note: DBCC: Database Concurrency Checker