ORACLE 表空间的有趣现象:最大使用率为负数

又到一年年底时,对数据库的健康检查必不可少,尤其是磁盘空间、asm 空间、表空间的检查与扩容。

平常 asm 磁盘/表空间的检查都很经常做,对于磁盘空间的检查可能没有那么关注,尤其是磁盘文件系统的 inode 使用情况,现在的磁盘都是白菜价,往往都是 2T 起步,根据经验 inode 在大磁盘的情况下,有时候超过50%之后就会有问题,可能出现创建文件很慢,比如创建 oracle的 audit 审计日志很慢,有超过 ext3/4 文件系统 的 Directory indexkernel: EXT4-fs warning (device dm-2): ext4_dx_add_entry: Directory index full! ,即使磁盘空间和文件系统的 inode 仍然很富裕的情况,参见:What is the meaning of “ext[3/4]_dx_add_entry: Directory index full!”? https://access.redhat.com/solutions/29894

检查 磁盘空间/inode 使用情况的时候,在批量机器进行检查的时候,尤其是堡垒机无法批量执行df 命令的时候,挨个去检查还是有点费时的。还有通常我们都是df -hdf -i 去检查,这样会将所有的磁盘的使用率展示出来,但是我只关注超过比如 磁盘使用率超过80%,inode使用率超过50%的情况。现在2023年都快结束了,AI 综合症都流行一年了,那就问下 AI吧。
简单方便,AI 第一次给我的命令如下比较简单明了:

1
df -h | awk '$5 > 80 {print}'

我复制到测试环境(Linux)去执行,没问题,能给出现预期的结果,我顺手在我的 MBP 上执行了一把,发现个奇怪的现象:

1
2
3
4
5
➜  ~df -h | awk '$5 > 80 {print}'
Filesystem Size Used Avail Capacity iused ifree %iused Mounted on
/dev/disk1s4 932Gi 6.0Gi 67Gi 9% 6 704M 0% /System/Volumes/VM
/dev/disk1s1 932Gi 846Gi 67Gi 93% 5.1M 704M 1% /System/Volumes/Data
/dev/disk2s2 511Mi 482Mi 29Mi 95% 478 4.3G 0% /Volumes/Seafile Client

发现其一块磁盘使用率为 9%的磁盘竟然展示出来了。然后,我就又问 AI :为什么 9% 的也展示出来了。

然后巴拉巴拉一堆,又给出了一个答案:
1
df -Ph | awk '$5 ~ /%/ && $5+0 > 80 {print}';df -i | awk '$5 ~ /%/ && $5+0 > 50 {print}'

当然为了展示好看,我又加上了 -P 参数,这样磁盘目录会展示在一行,方便观察,这样就只关注有结果的主机就好了。

下面说一下本次发现的一个奇怪的表空间的问题:

1
2
3
4
5
6
7
8
liups:/home/oracle>./ora tbs
Status Tablespace Name TS Type Ext. Mgt. Seg. Mgt. Tablespace Size MAX_MB Used (in MB) FREE_MB Pct. Used Pct. Free MAX_PCT_FREE

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

ONLINE ARCHIVE PERMANENT LOCAL AUTO 51,200 40960 42,789 8411 84 16 -4.47
ONLINE SYSAUX PERMANENT LOCAL AUTO 8,300 32768 6,954 1346 84 16 78.78
ONLINE INDEXES PERMANENT LOCAL AUTO 10,752 30720 9,983 769 93 7 67.5

可以看到这个ARCHIVE 表空间的 MAX_PCT_FREE 也就是最大可用空间的使用率是负数了。
然后可以看到表空间的当前大小比表空间的最大大小还大。看到这里就感觉比较神奇了,然后进一步查看数据文件的大小如下:

1
2
3
4
5
6
7
8
liups:/home/oracle>./ora dbf
Tablespace Name Filename File Size(MB) Auto Next (MB) Max (MB)

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

ARCHIVE /data/oradata/liups/archive01.dbf 30,720 YES 512 30,720
ARCHIVE /data/oradata/liups/archive02.dbf 20,480 YES 200 10,240

可以看到当前文件的大小确实比设置的最大大小要大,目前是 20g,数据文件的大小是10g。
好吧,那我们测试下是如何出现的这个情况。
数据库版本 19c

1
2
3
4
5
6
7
8
9
sys@ORA19CL 21:00:04> create tablespace mestbs  DATAFILE  SIZE 10M AUTOEXTEND ON NEXT 1K MAXSIZE 5m;
create tablespace mestbs DATAFILE SIZE 10M AUTOEXTEND ON NEXT 1K MAXSIZE 5m
*
ERROR at line 1:
ORA-02494: invalid or missing maximum file size in MAXSIZE clause

sys@ORA19CL 21:00:22> create tablespace mestbs DATAFILE SIZE 10M AUTOEXTEND ON NEXT 1K MAXSIZE 15m;

Tablespace created.

也就是在创建表空间的时候无法创建 maxsize 小于初始大小的数据文件。
那就测试下新增数据文件:

1
2
3
4
5
sys@ORA19CL 21:05:09>ALTER TABLESPACE mestbs ADD DATAFILE  SIZE 10M AUTOEXTEND ON NEXT 1K MAXSIZE 5M;
ALTER TABLESPACE mestbs ADD DATAFILE SIZE 10M AUTOEXTEND ON NEXT 1K MAXSIZE 5M
*
ERROR at line 1:
ORA-02494: invalid or missing maximum file size in MAXSIZE clause

可以看到在新增数据文件的时候也不能创建maxsize 小于初始大小的数据文件。
那就剩下一个编辑文件了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[oracle@liups:/home/oracle]$ ./ora.1 dbf

FILE# Tablespace Name Filename File Size(MB) Auto Next (MB) Max (MB)
---------- ------------------------------ --------------------------------------------------------------------------- ------------------ ---- ---------------- ----------------
10 MESTBS /data/oradata/ORA19CL/datafile/o1_mf_mestbs_lrwflfbk_.dbf 10 YES 0 15

sys@ORA19CL 21:09:50> ALTER DATABASE DATAFILE 10 AUTOEXTEND ON NEXT 8K MAXSIZE 9m;

Database altered.
[oracle@liups:/home/oracle]$ ./ora.1 dbf

FILE# Tablespace Name Filename File Size(MB) Auto Next (MB) Max (MB)
---------- ------------------------------ --------------------------------------------------------------------------- ------------------ ---- ---------------- ----------------
10 MESTBS /data/oradata/ORA19CL/datafile/o1_mf_mestbs_lrwflfbk_.dbf 10 YES 0 10

可以看到数据文件的 maxsize 是15m,数据文件是10m,然后执行设置其maxsize 为 9m,可以执行成功,但是坚持数据文件的属性的时候,发现其maxsize 由15m变成了10m,也就是虽然可以执行成功,但是maxsize 变成了数据文件的当前大小。

创建表空间的时候、新增数据文件的时候、修改maxsize的时候都无法把 maxsize 修改成小于数据文件的大小,那上面的例子是如何出现的呢,难道真的是自动扩展然后扩到当前的大小比maxsize还大,连测试都不用测试其实这是不可能。
最好想到了另一种情况,那就是 resize 当前的数据文件比maxsize大是不是可以呢。

1
2
3
4
5
6
sys@ORA19CL 21:19:18>  alter database datafile 10 resize 20m;
Database altered.
[oracle@liups:/home/oracle]$ ./ora.1 dbf
FILE# Tablespace Name Filename File Size(MB) Auto Next (MB) Max (MB)
---------- ------------------------------ --------------------------------------------------------------------------- ------------------ ---- ---------------- ----------------
10 MESTBS /data/oradata/ORA19CL/datafile/o1_mf_mestbs_lrwflfbk_.dbf 20 YES 0 10

然后可以看到,可以执行成功,然后会发现数据文件的大小比 maxsize的大小大了。这就解释了为什么表空间最大使用率为负数。