注册
达梦数据库:数据文件被删除后为什么还能插入数据?
培训园地/ 文章详情 /

达梦数据库:数据文件被删除后为什么还能插入数据?

codePanda 2025/12/11 217 2 0

在一次 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 文件的数据块并写入数据仍然写入这些内存缓存 + 未释放的数据区,这使数据看起来“一切正常”直到进程终止,这些匿名数据块才会被彻底释放。

此时数据库重启后,这些数据文件就真的彻底消失了。

四、利用 Linux FD 完整恢复被删的 DBF 文件(IO 重定向恢复法)

既然文件内容还存在于进程打开的 FD 中,我们就可以利用 /proc/&lt;pid>/fd 来恢复。

  1. 找到数据库进程
[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
  1. 查看被删除但仍被引用的 DBF 文件
lsof -p $DM_PID | grep DBF | grep deleted

输出示例:

dmserver 175629 ... /dm/data/DMDB/MAIN.DBF (deleted)
dmserver 175629 ... /dm/data/DMDB/DMHR.DBF (deleted)
...
  1. 编写恢复脚本 restore.sh
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
  1. 执行恢复
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% 成功的。**

六、社区地址

更多达梦技术分享:

https://eco.dameng.com

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服