利用dbcc writepage命令修改SQL SQLSERVER中的物理页面上的内容

dbcc writepage是sqlserver 2000 和 2005中未公开的命令,也就是说使用这些未官方支持的命令出现的任何后果与MS无关。

同样,本文仅仅演示dbcc writepage的使用,您在操作时出现的任何后果与本人无关。

dbcc writepage的语法为:

   dbcc writepage ({ dbid, ‘dbname’ }, fileid, pageid, offset, length, data)

下面演示dbcc writepage的使用方法:

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

第一步:创建一个测试表

1> create table test (id int not null,name varchar(30) null)
2> go
1> insert into test
2> select 1,'china'
3> go

(1 行受影响)
1> insert into test
2> select 2,'beijing'
3> go

(1 行受影响)

 

1> select object_id('test')
2> go

-----------
 1877581727

(1 行受影响)

表的ID为: 1877581727。


第二步:查看表内数据所在的页面号

1> select * from sysindexes
2> where id = 1877581727
3> go
id          status      first    indid  root     minlen keycnt groupid dpages
   reserved    used        rowcnt               rowmodctr   reserved3 reserved4
xmaxlen maxirow OrigFillFactor StatVersion reserved2   FirstIAM impid  lockflags
 pgmodctr    keys
                                                                name

                                 statblob

                                                    maxlen      rows
----------- ----------- -------- ------ -------- ------ ------ ------- ---------
-- ----------- ----------- -------------------- ----------- --------- ---------
------- ------- -------------- ----------- ----------- -------- ------ ---------
 ----------- -------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------- ----------------
--------------------------------------------------------------------------------
-------------------------------- -----------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------- ----------- -----------
 1877581727           0 0x3B4F00       0 0x000000      8      0       1
 1           2           2                    2           2         0         0
     57       0              0           0           0 0x3C4F00      0         0
           0 NULL
                                                               NULL

                                 NULL

                                                           8000           2

(1 行受影响)


查询属于test表的第一个数据页的页号,在sysindexes表中first列表示对象的第一个物理存储页的页号:0x384F00,也就是页号(1:20283)。

 

第三步:查询修改前的数据内容

下面查询修改前页面(1,20283)上的数据内容。可以看出(1,20283)页上有2行记录,这和插入的2行记录数保持一致。然后,观察到页面的头部有china和beijing的字样,

这和插入的2行记录内容“似乎”一致。


下面我用红色标记了test表中两行测试数据的内容。1,'china'    2,'beijing'

1> dbcc page(9,1,20283,2)
2> go

DATA:
Memory Dump @0x518FC000

518FC000:   01010400 00800001 00000000 00000800 ?................

518FC010:   00000000 00000200 aa000000 721f8a00 ?............r...

518FC020:   3b4f0000 01000000 92010000 75000000 ?;O..........u...

518FC030:   02000000 00000000 00000000 00000000 ?................

518FC040:   01000000 00000000 00000000 00000000 ?................

518FC050:   00000000 00000000 00000000 00000000 ?................

518FC060:   30000800 01000000 0200fc01 00140063 ?0..............c

518FC070:   68696e61 30000800 02000000 0200fc01 ?hina 0...........

518FC080:   00160062 65696a69 6e670000 21212121 ?...beijing ..!!!!

518FC090:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

518FC0A0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

........... 这些是未分配使用的空间

518FDFC0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

518FDFD0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

518FDFE0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

518FDFF0:   21212121 21212121 21212121 74006000 ?!!!!!!!!!!!!t.`.

OFFSET TABLE:

Row - Offset

1 (0x1) - 116 (0x74)

0 (0x0) - 96 (0x60)

DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

 

第四步:修改物理数据页面的内容

通过上面的dbcc page输出结果,仔细数了一下,china这列内容的偏移为111,将china这五个字符改成aaaa。这是最简单的。a的asicc为:97(0x61)。

1> db cc writepage(9,1,20283,111,5,0x6161616161)
2> go
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

 

第五步:查看修改后的物理页面的内容

1> dbcc page(9,1,20283,2)
2> go

DATA:
Memory Dump @0x5002C000

5002C000:   01010400 00820001 00000000 00000800 ?................

5002C010:   00000000 00000200 aa000000 721f8a00 ?............r...

5002C020:   3b4f0000 01000000 92010000 75000000 ?;O..........u...

5002C030:   02000000 00000000 00000000 8234666e ?.............4fn

5002C040:   00000000 00000000 00000000 00000000 ?................

5002C050:   00000000 00000000 00000000 00000000 ?................

5002C060:   30000800 01000000 0200fc01 00140061 ?0..............a

5002C070:   61616161 30000800 02000000 0200fc01 ?aaaa 0...........

5002C080:   00160062 65696a69 6e670000 21212121 ?...beijing ..!!!!

5002C090:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

5002C0A0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

5002C140:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

5002C150:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

..................省略未占用空间

5002DFE0:   21212121 21212121 21212121 21212121 ?!!!!!!!!!!!!!!!!

5002DFF0:   21212121 21212121 21212121 74006000 ?!!!!!!!!!!!!t.`.

OFFSET TABLE:

Row - Offset

1 (0x1) - 116 (0x74)

0 (0x0) - 96 (0x60)

DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

 

第六步:通过客户端工具验证修改后的数据内容

1> select * from test
2> go
id          name
----------- ------------------------------
          1 aaaaa
          2 beijing

(2 行受影响)
可以看到第一行记录的name列由china改为了aaaaa

备注: 以上演示的是仅仅修改某一行某一列的数据,并且修改后的内容和修改前的内容保持长度一致。

如果修改多列或者修改前后的字段长度不一致;进一步修改整行数据,或者修改整页的数据的话,可能会复杂许多。

————————————————————————————————-
—- 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
—- 转载务必注明原始出处 : http://www.dbainfo.net
—- 关键字:dbcc writepage undocumented command 修改 物理页面 page
————————————————————————————————-

  • 本文链接地址:https://www.dbainfo.net/direct-modify-sqlserver-data-page-by-dbcc-writepage.htm
  • 本文为dbainfo个人原创,请在尊重作者劳动成果的前提下进行转载;
  • 转载务必注明原始出处 : Sybase数据库技术,数据库恢复专家
  • 对《利用dbcc writepage命令修改SQL SQLSERVER中的物理页面上的内容》有何疑问或见解,请在本文下方发表;
  • 对网站还有其他问题或建议,请提交在留言板,谢谢!
    1. 不落的太远
      2012-06-04 12:54:50

      你好,想请问下dbcc page(9,1,20283,2),在此查询数据页中的数据,为什么我现在查不到?我现在是2012版本,不知道是不是版本的原因。还有个小问题,一个表中数据假如1W条,肯定会占据很多数据页,这个时候,我想知道多少条到多少条在哪个页上,这个你知道么,如果知道麻烦告诉下,谢谢。

      • dbainfo
        2012-06-04 19:29:59

        我测试的例子是查看数据库id=9,fileid=1,pageno=20283上的页面内容。你的环境中未必是该页!
        sqlserver 2012中肯定也有dbcc page这个命令,在执行dbcc page前别忘了先dbcc traceon(3604)!
        对于sqlserver来说,查找一个表所占用的所有页号,我不是太熟悉。我知道Sybase ASE中可以使用dbcc pglinkage()命令。不知道sqlserver是否有相似的命令?
        另外,可以采用比较一般的方法:通过查看某页上的前一页和后一页来遍历得到!

      • dbainfo
        2012-06-04 19:45:34

        建议看看sql server 2005 internals这本书!

    :wink: :twisted: :roll: :oops: :mrgreen: :lol: :idea: :evil: :cry: :arrow: :?: :-| :-x :-o :-P :-D :-? :) :( :!: 8-O 8)