对于一张表的数据,数据库是如何寻址并读取到其真实的数据,这便是寻址方式, 寻找到表数据的物理地址后dump出相关的内容。
CREATE TABLESPACE "DMUPUSER.DBF" DATAFILE 'DMUPUSER.DBF' SIZE 128 CACHE = NORMAL;
create user "DMUPUSER" identified by "123456789"
default tablespace "DMUPUSER.DBF"
default index tablespace "DMUPUSER.DBF";
grant "PUBLIC","SOI" to "DMUPUSER";
---建表测试表PAGETEST、插入数据
create table "DMUPUSER"."PAGETEST"
(
"C1" INT,
"C2" VARCHAR(50),
"C3" INT
)
storage(initial 1, next 1, minextents 1, fillfactor 0, on "DMUPUSER.DBF")
;
-- 建表PAGETEST_DEL并插入数据在删除
create table "DMUPUSER"."PAGETEST_DEL"
(
"C1" INT,
"C2" VARCHAR(50),
"C3" INT
)
storage(initial 1, next 1, minextents 1, fillfactor 0, on "DMUPUSER.DBF")
;
INSERT INTO "DMUPUSER"."PAGETEST_DEL" SELECT LEVEL,LEVEL,LEVEL FROM DUAL CONNECT BY LEVEL <1000;
DROP TABLE "DMUPUSER"."PAGETEST_DEL";
INSERT INTO "DMUPUSER"."PAGETEST" SELECT LEVEL,LEVEL,LEVEL FROM DUAL CONNECT BY LEVEL <100000000;
commit;
select checkpoint(100);
说明
思路:主要是操作SYSOBJECTS表,该表记录系统中所有对象的信息,可以找到表的根页号从而导出表的数据页。这种方式导出数据页,可能是错误的。因为表在物理上不一定是连续的,也会出现跨段等情况。
-- 以DMUPUSER用户为例
select ID from SYSOBJECTS where name = 'PAGETEST' AND TYPE$ = 'SCH';
-- 以DMUPUSER用户的PAGETEST表为例
SELECT ID FROM SYSOBJECTS WHERE NAME='PAGETEST' AND SCHID = (select ID from SYSOBJECTS where name = 'DMUPUSER' AND TYPE$ = 'SCH')
-- 以DMUPUSER用户的DMUP_TEST01表为例
SELECT *
FROM SYSINDEXES
WHERE ID =(SELECT ID
FROM SYSOBJECTS
WHERE PID=(SELECT ID
FROM SYSOBJECTS
WHERE NAME='PAGETEST'
AND SCHID = (select ID from SYSOBJECTS where name = 'DMUPUSER' AND TYPE$ = 'SCH'))
ORDER BY ID LIMIT 1)
select * from V$DATAFILE WHERE GROUPID = :GROUP_ID AND ID = :ROOTFILE
以上组合后的语句
-- 以DMUPUSER用户的DMUP_TEST01表为例
select * , ( select CLIENT_PATH
from V$DATAFILE
WHERE GROUP_ID = t.GROUPID
AND ID = t.ROOTFILE) TABLESPACES_NAME
from ( SELECT *
FROM SYSINDEXES
WHERE ID =(SELECT ID
FROM SYSOBJECTS
WHERE PID=(SELECT ID
FROM SYSOBJECTS
WHERE NAME='PAGETEST'
AND SCHID = (select ID from SYSOBJECTS where name = 'DMUPUSER' AND TYPE$ = 'SCH'))
ORDER BY ID LIMIT 1)) t
查询结果说明:DMUPUSER用户的PAGETEST表在数据文件DMUPUSER.DBF中,数据的根页为16 (ROOTPAGE字段)。
dd if=DMUPUSER.DBF of=test1.txt skip=`echo 16*8192|bc` ibs=1 count=8192;
注意:
命令解析
dd 是 Linux 系统中的一个命令,用于进行数据转换和复制。
## 1. 导出数据执行
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test1.txt skip=`echo 32*8192|bc` ibs=1 count=8192;
记录了8192+0 的读入
记录了16+0 的写出
8192字节(8.2 kB,8.0 KiB)已复制,0.00365255 s,2.2 MB/s
## 2. 使用xxd命令查看二进制文件,可以观察到insert的DUMP_STR可以在二进制中看到
[root@localhost DAMENG]# xxd test1.txt
00000000: 0b00 0000 2000 0000 ffff ffff ffff ffff .... ...........
00000010: ffff ffff 1500 0000 75c1 2341 abc4 f400 ........u.#A....
00000020: 0000 0000 0400 371c 0000 0000 0200 8000 ......7.........
00000030: 5200 5a00 0000 9000 0300 f70f 0002 0b00 R.Z.............
00000040: 0000 0800 0000 0c01 0b00 0000 0800 0000 ................
00000050: c400 4f43 0a00 0000 0000 ffff ffff ffff ..OC............
00000060: ffff 000f 0080 5d0a 0000 0091 d4ab 0200 ......].........
00000070: 0000 0f00 1cc3 0d00 0000 0e0e 5205 0000 ............R...
00000080: 000f 008f 000a 0000 00fc 8ba7 0200 0000 ................
00000090: 0f00 9e00 0a00 0000 751e a602 0000 000f ........u.......
000000a0: 00ad 000a 0000 00ee b0a4 0200 0000 0f00 ................
000000b0: bc00 0a00 0000 6743 a302 0000 000f 00cb ......gC........
000000c0: 000a 0000 00e0 d5a1 0200 0000 0f00 da00 ................
000000d0: 0a00 0000 5968 a002 0000 000f 00e9 000a ....Yh..........
000000e0: 0000 00d2 fa9e 0200 0000 0f00 f800 0a00 ................
000000f0: 0000 4b8d 9d02 0000 000f 0007 010a 0000 ..K.............
00000100: 00c4 1f9c 0200 0000 0f00 1601 0a00 0000 ................
00000110: 3db2 9a02 0000 000f 0025 010a 0000 00b6 =........%......
00000120: 4499 0200 0000 0f00 3401 0a00 0000 2fd7 D.......4...../.
00000130: 9702 0000 000f 0043 010a 0000 00a8 6996 .......C......i.
00000140: 0200 0000 0f00 5201 0a00 0000 21fc 9402 ......R.....!...
00000150: 0000 000f 0061 010a 0000 009a 8e93 0200 .....a..........
00000160: 0000 0f00 7001 0a00 0000 1321 9202 0000 ....p......!....
00000170: 000f 007f 010a 0000 008c b390 0200 0000 ................
00000180: 0f00 8e01 0a00 0000 0546 8f02 0000 000f .........F......
00000190: 009d 010a 0000 007e d88d 0200 0000 0f00 .......~........
000001a0: ac01 0a00 0000 f76a 8c02 0000 000f 00bb .......j........
000001b0: 010a 0000 0070 fd8a 0200 0000 0f00 ca01 .....p..........
000001c0: 0a00 0000 e98f 8902 0000 000f 00d9 010a ................
000001d0: 0000 0062 2288 0200 0000 0f00 e801 0a00 ...b"...........
000001e0: 0000 dbb4 8602 0000 000f 00f7 010a 0000 ................
000001f0: 0054 4785 0200 0000 0f00 0602 0a00 0000 .TG.............
00000200: cdd9 8302 0000 000f 0015 020a 0000 0046 ...............F
00000210: 6c82 0200 0000 0f00 2402 0a00 0000 bffe l.......$.......
00000220: 8002 0000 000f 0033 020a 0000 0038 917f .......3.....8..
00000230: 0200 0000 0f00 4202 0a00 0000 b123 7e02 ......B......#~.
00000240: 0000 000f 0051 020a 0000 002a b67c 0200 .....Q.....*.|..
思路:查询表的聚集索引的ID,通过v$segmentinfo表查看该索引ID所有的段ID以及物理页号。
select OBJECT_ID,INDEX_NAME,INDEX_TYPE,OBJECT_TYPE,INDEX_TYPE,
UNIQUENESS from dba_indexes a,dba_objects b where TABLE_NAME='PAGETEST' and a.INDEX_NAME=B.OBJECT_NAME and b.owner = 'DMUPUSER' AND INDEX_TYPE = 'CLUSTER' AND INDEX_NAME LIKE 'INDEX%';
-- 以DMUPUSER用户的PAGETEST表为例
select * from v$segmentinfo where index_id=( select OBJECT_ID from dba_indexes a,dba_objects b where TABLE_NAME='PAGETEST' and a.INDEX_NAME=B.OBJECT_NAME and b.owner = 'DMUPUSER' AND INDEX_TYPE = 'CLUSTER' AND INDEX_NAME LIKE 'INDEX%' );
-- 如需要确认数据表所在的数据文件,可根据查询结果的FIL_ID字段查询V$DATAFILE表查看表空间名称
-- 批量生成dd命令的脚本请查看附录
查询结果说明
使用如下命令
dd if=DMUPUSER.DBF of=test1.txt skip=`echo 96*8192|bc` ibs=1 count=8192;
注意:
命令解析
dd 是 Linux 系统中的一个命令,用于进行数据转换和复制。
## 1. 导出数据执行
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test1.txt skip=`echo 4528*8192|bc` ibs=1 count=8192;
记录了8192+0 的读入
记录了16+0 的写出
8192字节(8.2 kB,8.0 KiB)已复制,0.0036946 s,2.2 MB/s
## 2. 使用xxd命令查看二进制文件,可以观察到insert的DUMP_STR可以在二进制中看到
[root@localhost DAMENG]# xxd test1.txt
00000000: 0b00 0000 b011 0000 ffff ffff ffff 0000 ................
00000010: b111 0000 1400 0000 b9a2 a3d0 bbcd cf00 ................
00000020: 0000 0000 e500 1c1e 0000 0000 e300 ffff ................
00000030: 5200 5a00 0000 ee1f 0000 f70f 0002 0000 R.Z.............
00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000050: 0000 0000 0000 0000 0000 ffff ffff ffff ................
00000060: ffff 0020 0001 0000 0001 0000 0081 3101 ... ..........1.
00000070: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000080: 0000 0020 0002 0000 0002 0000 0081 3202 ... ..........2.
00000090: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
000000a0: 0000 0020 0003 0000 0003 0000 0081 3303 ... ..........3.
000000b0: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
000000c0: 0000 0020 0004 0000 0004 0000 0081 3404 ... ..........4.
000000d0: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
000000e0: 0000 0020 0005 0000 0005 0000 0081 3505 ... ..........5.
000000f0: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000100: 0000 0020 0006 0000 0006 0000 0081 3606 ... ..........6.
00000110: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000120: 0000 0020 0007 0000 0007 0000 0081 3707 ... ..........7.
00000130: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000140: 0000 0020 0008 0000 0008 0000 0081 3808 ... ..........8.
00000150: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000160: 0000 0020 0009 0000 0009 0000 0081 3909 ... ..........9.
00000170: 0000 0000 00ff ffff ff7f ffff e829 1100 .............)..
00000180: 0000 0021 000a 0000 000a 0000 0082 3130 ...!..........10
00000190: 0a00 0000 0000 ffff ffff 7fff ffe8 2911 ..............).
000001a0: 0000 0000 2100 0b00 0000 0b00 0000 8231 ....!..........1
000001b0: 310b 0000 0000 00ff ffff ff7f ffff e829 1..............)
000001c0: 1100 0000 0021 000c 0000 000c 0000 0082 .....!..........
000001d0: 3132 0c00 0000 0000 ffff ffff 7fff ffe8 12..............
000001e0: 2911 0000 0000 2100 0d00 0000 0d00 0000 ).....!.........
000001f0: 8231 330d 0000 0000 00ff ffff ff7f ffff .13.............
00000200: e829 1100 0000 0021 000e 0000 000e 0000 .).....!........
00000210: 0082 3134 0e00 0000 0000 ffff ffff 7fff ..14............
00000220: ffe8 2911 0000 0000 2100 0f00 0000 0f00 ..).....!.......
00000230: 0000 8231 350f 0000 0000 00ff ffff ff7f ...15...........
00000240: ffff e829 1100 0000 0021 0010 0000 0010 ...).....!......
00000250: 0000 0082 3136 1000 0000 0000 ffff ffff ....16..........
00000260: 7fff ffe8 2911 0000 0000 2100 1100 0000 ....).....!.....
00000270: 1100 0000 8231 3711 0000 0000 00ff ffff .....17.........
00000280: ff7f ffff e829 1100 0000 0021 0012 0000 .....).....!....
00000290: 0012 0000 0082 3138 1200 0000 0000 ffff ......18........
000002a0: ffff 7fff ffe8 2911 0000 0000 2100 1300 ......).....!...
000002b0: 0000 1300 0000 8231 3913 0000 0000 00ff .......19.......
000002c0: ffff ff7f ffff e829 1100 0000 0021 0014 .......).....!..
000002d0: 0000 0014 0000 0082 3230 1400 0000 0000 ........20......
000002e0: ffff ffff 7fff ffe8 2911 0000 0000 2100 ........).....!.
dd if=DMUPUSER.DBF of=test1.txt skip=`echo 16*8192|bc` ibs=1 count=81920;
v$segmentinfo表的方式,导出10个数据块
使用脚本生成的命令
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 16*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 97*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 98*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 99*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 100*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 101*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 102*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 103*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 104*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 105*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# dd if=DMUPUSER.DBF of=test2.txt skip=`echo 106*8192|bc` ibs=1 count=8192 conv=notrunc oflag=append;
[root@localhost DAMENG]# xxd test2.txt | grep -v '0000 0000 0000 0000 0000 0000 0000 0000' |head -n 1100| tail -n 100
两个文本比较,查看第1000行对比如下:
/**
修改三个参数
table_owner 模式名
table_name 表名
print_count 要打印的页数
**/
declare
table_owner varchar(256);
table_name varchar(256);
datafile_name varchar(256);
sql_str varchar(512);
page_size int;
i NUMBER := 0;
print_count int;
PHY_PAGE_NO int;
CURSOR sel_cur;
begin
table_owner := 'DMUPUSER';
table_name := 'PAGETEST';
print_count := 10;
-- 查询出表所在的表空间
sql_str:= 'select tablespace_name from dba_indexes where table_owner =''' || table_owner || ''' AND INDEX_TYPE = ''CLUSTER''' || ' AND INDEX_NAME LIKE ''INDEX%''' || 'AND TABLE_NAME = ''' || table_name||'''';
--print 'sql_str' || sql_str;
execute immediate sql_str into datafile_name;
-- 查询出当前页大小
select page into page_size from dual;
--PRINT 'datafile_name=' || datafile_name;
-- 查询块sql
sql_str:= 'select PHY_PAGE_NO from v$segmentinfo where index_id=( select OBJECT_ID from dba_indexes a,' || 'dba_objects b where TABLE_NAME=''' ||table_name|| ''' and a.INDEX_NAME=B.OBJECT_NAME and b.owner = ''' || table_owner || ''' AND INDEX_TYPE = ''CLUSTER'' AND INDEX_NAME LIKE ''INDEX%'' )';
--PRINT 'sql_str ' || sql_str;
open sel_cur for sql_str;
LOOP
FETCH sel_cur INTO PHY_PAGE_NO;
EXIT WHEN sel_cur%NOTFOUND OR i >print_count ;
i := i + 1;
print 'dd if=' || datafile_name || ' of=test1.txt skip=`echo '||PHY_PAGE_NO||'*'||page_size||'|bc` ibs=1 count='||page_size||' conv=notrunc oflag=append;';
END LOOP;
CLOSE sel_cur;
end;
dd两个命令介绍,使用下方命令参数可将源文件的内容追加到目标文件的末尾,并保留目标文件原有的内容。
## 备用命令
## 1. 查看文件时,去除空数据
[root@localhost DAMENG]# xxd test1.txt | grep -v '0000 0000 0000 0000 0000 0000 0000 0000' |head -n 100
## 2. 查看前几行
[root@localhost DAMENG]# xxd test1.txt|head -n 50
## 3. hexdump命令
[root@localhost DAMENG]# hexdump -C test1.txt
## hexdump -C 参数是 hexdump 命令的一个选项,表示以十六进制和 ASCII 的形式显示文件内容,每行显示对应的 ASCII 字符。