在一次 DCA 实验中,我意外发现一个“反直觉”现象:把表空间的数据文件从操作系统层面删除后,数据库竟然还能正常插入数据,并且查询结果正常返回。
这引发了一个问题:
数据文件都没了,数据库到底把数据写到哪里去了?为什么还能“正常工作”?
以下操作在数据库正常运行状态下进行,删除数据文件(OS 层面)
[dmdba@panda51:/dm/data/DMDB]$ rm -rf TBS0
[dmdba@panda51:/dm/data/DMDB]$ rm -rf MAIN.DBF
[dmdba@panda51:/dm/data/DMDB]$ rm -rf DMHR.DBF
[dmdba@panda51:/dm/data/DMDB]$ ll
# 可以看到文件已确实从磁盘删除
总用量 8605896
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 bak
drwxr-xr-x 2 dmdba dinstall 4096 11月 15 00:59 ctl_bak
-rw-r--r-- 1 dmdba dinstall 337 11月 14 23:14 dmarch.ini
-rw-r--r-- 1 dmdba dinstall 7168 11月 15 00:59 dm.ctl
-rw-r--r-- 1 dmdba dinstall 4294967296 11月 15 01:39 DMDB01.log
-rw-r--r-- 1 dmdba dinstall 4294967296 11月 15 00:59 DMDB02.log
-rw-r--r-- 1 dmdba dinstall 85018 11月 15 00:59 dm.ini
-rw-r--r-- 1 dmdba dinstall 85024 11月 14 23:14 dm.ini.dmbak
-rw-r--r-- 1 dmdba dinstall 900 11月 14 22:22 dminit_DMDB_20251114222219.log
-rw-r--r-- 1 dmdba dinstall 633 11月 14 22:22 dm_service.prikey
-rw-r--r-- 1 dmdba dinstall 3072 11月 14 22:22 dmtemp.ctl
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 HMAIN
-rw-r--r-- 1 dmdba dinstall 134217728 11月 15 01:38 ROLL.DBF
-rw-r--r-- 1 dmdba dinstall 714 11月 14 22:22 sqllog.ini
-rw-r--r-- 1 dmdba dinstall 77594624 11月 15 01:32 SYSTEM.DBF
-rw-r--r-- 1 dmdba dinstall 10485760 11月 15 00:59 TEMP.DBF
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 trace
数据库层面操作仍然正常查询表空间:
SQL> select TABLESPACE_NAME from dba_tables where table_name='T1';
行号 TABLESPACE_NAME
---------- ---------------
1 MAIN
SQL> select * from dmhr.t1;
未选定行
已用时间: 0.498(毫秒). 执行号:2204.
SQL> insert into dmhr.t1 values(1);
影响行数 1
已用时间: 1.808(毫秒). 执行号:2205.
SQL>
SQL> commit;
已用时间: 22.112(毫秒). 执行号:2215.
SQL>
SQL> insert into dmhr.t1 values (2);
影响行数 1
已用时间: 3.834(毫秒). 执行号:2216.
SQL> commit;
操作已执行
已用时间: 2.886(毫秒). 执行号:2217.
SQL> select * from dmhr.t1;
行号 ID
---------- -----------
1 1
2 2
神奇:数据文件被删了,表还能用。
<font style="color:rgb(34, 34, 34);">但是此时已经没有办法联机备份了</font>
SQL> backup database full to "backup_set_2_full_20251118" backupset '/dm/backup/backup_set_2_full_20251118';
backup database full to "backup_set_2_full_20251118" backupset '/dm/backup/backup_set_2_full_20251118';
[-3432]:使用了不可修改的表空间,该表空间处于离线状态或数据文件被删除.
已用时间: 00:00:02.070. 执行号:0.
说明数据库内部已经感知到数据文件异常,只是尚未完全崩溃。更严重的是:此时发生的事务在数据库重启后全部丢失!即使使用旧备份 + 增量日志也无法完全恢复。
核心原因不是数据库“厉害”,而是 Linux 的文件系统机制,Linux 文件删除不等于内容立即消失,当进程打开文件后(如数据库数据文件),OS 会维持一个 file descriptor(文件句柄)。即使执行了 rm 把文件名从目录删除:文件数据仍然存在 inode 中,只要有进程仍持有文件句柄,文件内容仍然可读写
通过 lsof 能看到:
dmserver 175629 ... /dm/data/DMDB/MAIN.DBF (deleted)
只要数据库进程没退出,内核仍保持着这些 .DBF 文件的数据块并写入数据仍然写入这些内存缓存 + 未释放的数据区,这使数据看起来“一切正常”直到进程终止,这些匿名数据块才会被彻底释放。
此时数据库重启后,这些数据文件就真的彻底消失了。
既然文件内容还存在于进程打开的 FD 中,我们就可以利用 /proc/<pid>/fd 来恢复。
[dmdba@panda51:/dm/data/DMDB]$ ps -ef | grep dmserver
dmdba 175629 1 0 ... /dm/bin/dmserver path=/dm/data/DMDB/dm.ini -noconsole
设置 PID:
DM_PID=175629
lsof -p $DM_PID | grep DBF | grep deleted
输出示例:
dmserver 175629 ... /dm/data/DMDB/MAIN.DBF (deleted)
dmserver 175629 ... /dm/data/DMDB/DMHR.DBF (deleted)
...
vi restore.sh
脚本内容:
DM_PID=$(ps -ef | grep dmserver | grep -v grep | awk '{print $2}')
RESTORE_DIR="/dm/data/DMDB"
lsof -p $DM_PID | grep DBF | grep deleted | while read line
do
FD=$(echo $line | awk '{print $4}' | tr -d 'u')
FILE=$(echo $line | awk '{print $9}' | sed 's/(deleted)//')
BASENAME=$(basename $FILE)
cp /proc/$DM_PID/fd/$FD $RESTORE_DIR/$BASENAME
done
chown dmdba:dinstall $RESTORE_DIR/*.DBF
chmod 660 $RESTORE_DIR/*.DBF
sh restore.sh
ll -lrt
可以看到 DBF 文件被成功重新生成:
[dmdba@panda51:/dm/data/DMDB]$ ll -lrt
总用量 8999116
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 bak
-rw-r--r-- 1 dmdba dinstall 714 11月 14 22:22 sqllog.ini
-rw-r--r-- 1 dmdba dinstall 633 11月 14 22:22 dm_service.prikey
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 HMAIN
-rw-r--r-- 1 dmdba dinstall 900 11月 14 22:22 dminit_DMDB_20251114222219.log
-rw-r--r-- 1 dmdba dinstall 3072 11月 14 22:22 dmtemp.ctl
drwxr-xr-x 2 dmdba dinstall 6 11月 14 22:22 trace
-rw-r--r-- 1 dmdba dinstall 85024 11月 14 23:14 dm.ini.dmbak
-rw-r--r-- 1 dmdba dinstall 337 11月 14 23:14 dmarch.ini
-rw-r--r-- 1 dmdba dinstall 85018 11月 15 00:59 dm.ini
-rw-rw---- 1 dmdba dinstall 10485760 11月 15 00:59 TEMP.DBF
-rw-r--r-- 1 dmdba dinstall 4294967296 11月 15 00:59 DMDB02.log
-rw-r--r-- 1 dmdba dinstall 7168 11月 15 00:59 dm.ctl
drwxr-xr-x 2 dmdba dinstall 4096 11月 15 00:59 ctl_bak
-rw-rw---- 1 dmdba dinstall 77594624 11月 15 01:50 SYSTEM.DBF
-rw-r--r-- 1 dmdba dinstall 433 11月 15 01:56 restore.sh
-rw-rw---- 1 dmdba dinstall 134217728 11月 15 01:56 ROLL.DBF
-rw-r--r-- 1 dmdba dinstall 4294967296 11月 15 01:56 DMDB01.log
-rw-rw---- 1 dmdba dinstall 134217728 11月 15 01:56 MAIN.DBF
-rw-rw---- 1 dmdba dinstall 134217728 11月 15 01:56 DMHR.DBF
-rw-rw---- 1 dmdba dinstall 67108864 11月 15 01:56 TBS01.DBF
-rw-rw---- 1 dmdba dinstall 67108864 11月 15 01:56 TBS02.DBF
恢复后执行全量备份
backup database full to "backup_set_2_full_20251118"
backupset '/dm/backup/backup_set_2_full_20251118';
重启数据库
DmServicePROD stop
DmServicePROD start
查询数据:
select * from dmhr.t1;
1
2
数据完全恢复。
注意此操作不一定100%恢复,必须数据库进程仍然持有文件句,确认DMServer 没有关闭文件描述符没有释放,OS 会保持文件 inode 存在可以从 /proc/pid/fd/xxx 复制出来。
** 文件删除后还能写入是因为 OS 缓存与文件句柄依然存在; 但从缓存复制出来的 DBF 不一定完整,不一定一致,所以恢复方案不是 100% 成功的。**
更多达梦技术分享:
文章
阅读量
获赞
