ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Oracle ORA-01119目录不存在报错解析:OMF与RAC环境表空间创建实战

Oracle ORA-01119目录不存在报错解析:OMF与RAC环境表空间创建实战 上周一刚进办公室值班同事甩来一条消息客户那边建表空间又报错了ORA-01119后面跟着一串Linux Error: 2: No such file or directory。我一看就明白又是“目录不存在”。这类报错在Oracle运维里太常见了单机环境还好说真正让人头疼的是RAC环境——两个节点路径不一致、共享存储没挂全、ASM目录层级没建好都会导致同样的错误。今天我就把这次“表空间创建体验升级”的前因后果、具体方案和踩过的坑一次性说清楚。很多DBA习惯把“目录不存在”当成低级问题但它每年都能坑到不少老手。原因很简单Oracle不像MySQL那样把数据文件集中放在datadir下数据文件的路径完全由DBA指定目录规划好不好、各节点是否一致直接决定了你创建表空间时会不会被ORA-01119打断。这篇文章我会拆解这个问题的根因分享一套从“人肉确认目录”升级为“系统自动兜底”的方案并附上RAC环境表空间满了之后的清理套路希望能帮你少接几个半夜值班电话。1. 80%的人都遇过的“目录不存在”到底卡在哪1.1 一个典型的报错现场先还原一下最常见的场景。你执行了一条再普通不过的建表空间语句SQL CREATE TABLESPACE tbs_app DATAFILE /u01/oradata/orcl/tbs_app01.dbf SIZE 10G;然后Oracle毫不留情地甩回三行错误ORA-01119: error in creating database file /u01/oradata/orcl/tbs_app01.dbf ORA-27040: file create error, unable to create file Linux-x86_64 Error: 2: No such file or directory第三行才是真正的操作系统层信息No such file or directory。翻译成人话就是你让Oracle去/u01/oradata/orcl/下创建文件但这个目录不存在或者Oracle进程根本没权限看到它。我第一次遇到这个报错时第一反应是“不可能啊我明明建过目录”。后来一查发现自己在另一台机器上建的目录而当前连接的节点上压根没建。这个细节在单机环境不易暴露一旦到了RAC或者Data Guard环境就会被无限放大。1.2 藏在报错后面的三类真实原因根据我这些年排查的经验“目录不存在”这个报错背后90%的情况跑不出以下三类原因第一类是目录确实没建。新装的环境、新挂的磁盘DBA凭记忆写了路径但对应的目录根本不存在。这种情况最直接也最好解决。第二类是目录存在但权限不够。注意这时候报错不一定是“No such file or directory”也可能是Permission denied。很多新手分不清这两个错误其实逻辑完全不一样一个是路径压根没有另一个是路径在但你进不去。排查手段很简单用ls -ld看目录权限用id oracle确认oracle用户是否在正确的组里。第三类最坑出现在RAC环境目录在节点1存在但节点2上没有或者目录在共享存储上但其中一个节点挂载失败。RAC的多个实例共享同一套数据文件你通过节点1执行建表空间语句文件实际可能写在节点1本地盘上节点2根本访问不到。这种问题不会马上报错而是会在failover或者后续操作时突然爆发。理解这三类原因后你会发现这类问题的本质不是Oracle本身有多复杂而是“路径管理”这件事过度依赖人工。人一旦受累、疏忽目录就会出问题。所以我的升级思路也很直接把目录的确认和创建从DBA的手动工作变成数据库和脚本的自动行为。2. 创建表空间的体验升级三层防护设计2.1 第一层OMF接管文件路径目录消失不再是问题先说这次升级里最核心的一招启用OMFOracle Managed FilesOracle托管文件。OMF的核心理念是数据文件在哪、叫什么名字由Oracle自己决定DBA只需要告诉它“放哪个目录”或“放哪个磁盘组”。启用方式很简单在数据库层面设置两个参数SQL ALTER SYSTEM SET DB_CREATE_FILE_DESTDATA SCOPEBOTH;或者如果你用文件系统SQL ALTER SYSTEM SET DB_CREATE_FILE_DEST/u01/oradata/orcl SCOPEBOTH;设置之后创建表空间的SQL可以简化为SQL CREATE TABLESPACE tbs_app SIZE 10G;不需要指定DATAFILE不需要关心文件名Oracle会自动在当前默认目录下生成一个唯一命名的数据文件并且自动创建必要的目录结构尤其是在ASM里。这样一来“目录不存在”这个问题在OMF模式下从源头被消灭了——你根本没机会手动写错路径。这里我做个对比方便你理解OMF和手工指定路径的差异对比项手工指定DATAFILEOMF托管指定路径必须精确到文件名只需指定DB_CREATE_FILE_DEST目录检查DBA自己负责Oracle自动处理文件名冲突容易踩坑自动生成唯一名删除表空间文件残留风险高数据文件自动清理适合场景需要精细控制文件分布追求规范、省心的运维环境很多人担心OMF会让自己失去对文件名的控制。我的看法是生产环境里“可控”的价值远大于“文件名好看”。OMF生成的文件名虽然是一串带时间戳的随机字符但你在DBA_DATA_FILES里照样能查到对应关系出问题时定位并不难。2.2 第二层统一目录规范用脚本自动兜底OMF虽然好用但现实环境里总会遇到一些无法启用OMF的情况比如历史库没开OMF、某些特殊表空间需要固定文件路径、或者DBA团队习惯手工管理。这时候第二层防护就派上用场了把目录检查和创建做成自动化脚本让它成为建表空间流程的固定前置步骤。先定目录规范。我一般在文件系统上强制要求所有Oracle数据文件统一放在/u01/oradata/ORACLE_SID/下临时文件放/u01/oradata/ORACLE_SID/temp/控制文件和redo另放目录避免混在一起。目录命名用小写不使用中文和特殊符号所有节点一致。然后写一个简单的检查脚本核心逻辑就是“目录不存在就创建已存在就确认权限”。下面是我常用的一段简化版#!/bin/bash # check_dir.sh - 自动检查并创建数据文件目录 ORACLE_SIDorcl DATA_DIR/u01/oradata/${ORACLE_SID} for dir in ${DATA_DIR} ${DATA_DIR}/temp; do if [ ! -d ${dir} ]; then echo [INFO] Directory ${dir} does not exist, creating... mkdir -p ${dir} else echo [INFO] Directory ${dir} already exists. fi chown oracle:oinstall ${dir} chmod 775 ${dir} done这段脚本没什么高深技术但它解决了一个非常现实的问题你再也不用在每次建表空间前手动执行mkdir -p也不用担心漏掉某个节点。把它放进发布流程所有DBA建表空间前先跑一遍目录层面的报错会大幅减少。2.3 第三层ASM目录管理与权限校验如果你的Oracle跑在ASM自动存储管理上目录的故事又不一样了。ASM里没有传统的文件和目录概念它用磁盘组加目录层级来组织文件路径看起来像DATA/ORCL/DATAFILE/tbs_app01.dbf。ASM环境下遇到“目录不存在”通常有两种情况一是磁盘组本身不存在或没挂载二是磁盘组存在但目录层级没建好。磁盘组不存在会报ORA-15018diskgroup does not exist or is not mounted这类问题你得先检查磁盘组状态SQL SELECT name, state, total_mb, free_mb FROM v$asm_diskgroup;如果磁盘组正常只是目录没建好可以用ASMCMD手动建目录也可以用SQL直接操作。我的习惯是先把目录层级一次性建好避免每次创建表空间时都去纠结路径$ asmcmd ASMCMD ls DATA ASMCMD mkdir DATA/ORCL ASMCMD mkdir DATA/ORCL/DATAFILE ASMCMD mkdir DATA/ORCL/TEMPFILE这里有个容易忽略的点ASM目录权限和文件系统不一样普通Oracle用户对目录的操作权限受ASM实例的权限模型控制。如果你用sqlplus / as sysdba操作通常没问题但如果是普通DBA账号可能需要额外的ASM权限否则即使目录存在也会报权限相关错误。所以在ASM环境下校验目录是否存在、磁盘组是否可写、用户是否有权限这三件事缺一不可。3. 一次完整的“升级版”表空间创建实操3.1 动手前先确认环境不管用OMF还是脚本动手之前花两分钟确认环境都值得。我会依次检查三件事第一当前连接的实例是不是目标环境别在一个库上操作半天才发现连错了第二存储层面是否就绪文件系统看挂载、ASM看磁盘组状态第三参数是否到位重点看DB_CREATE_FILE_DEST、DB_CREATE_ONLINE_LOG_DEST_n这些和文件路径有关的参数。检查SQL如下SQL SHOW PARAMETER DB_CREATE_FILE_DEST; SQL SELECT name, value FROM v$parameter WHERE name LIKE db_create%;如果OMF参数没设置但你确定要改成OMF模式执行前面提过的ALTER SYSTEM SET DB_CREATE_FILE_DEST...即可。这里提醒一句更改参数后最好确认一下所有RAC节点都生效用SHOW PARAMETER在每个节点上各查一遍最稳妥。3.2 用OMF方式创建表空间一条SQL完成环境无误后创建表空间就变成了一个非常清爽的操作。假设我要创建一个应用表空间tbs_app初始大小10G允许自动扩展最大扩展到32GSQL CREATE TABLESPACE tbs_app DATAFILE SIZE 10G AUTOEXTEND ON NEXT 512M MAXSIZE 32G;注意在OMF模式下DATAFILE子句后面可以不跟具体路径直接跟SIZE参数。Oracle会在DB_CREATE_FILE_DEST指定的目录下自动生成文件。创建完成后用下面这段SQL验证一下文件到底落在哪了SQL SELECT tablespace_name, file_name, bytes/1024/1024/1024 AS size_gb FROM dba_data_files WHERE tablespace_name TBS_APP;你会在FILE_NAME列看到类似/u01/oradata/orcl/datafile/o1_mf_tbs_app_xxxxxx.dbf的路径在ASM环境则是DATA/ORCL/DATAFILE/xxxxx。文件名虽然是一串随机字符但这不碍事所有管理操作照样可以通过表空间名和视图完成。3.3 非OMF场景脚本自动建目录再建表空间如果你所在的环境仍然采用手工指定路径的方式那我的建议是把这个动作做成一个固定套路。下面是我实际在用的一个组合脚本核心逻辑就是“先检查目录再执行建表空间SQL”#!/bin/bash # create_tbs.sh # 用法: ./create_tbs.sh tbs_app 10G 512M 32G TBS_NAME$1 INIT_SIZE$2 NEXT_SIZE$3 MAX_SIZE$4 ORACLE_SIDorcl DATA_DIR/u01/oradata/${ORACLE_SID} DATA_FILE${DATA_DIR}/${TBS_NAME}01.dbf # 第一步检查并创建目录 if [ ! -d ${DATA_DIR} ]; then mkdir -p ${DATA_DIR} chown oracle:oinstall ${DATA_DIR} fi # 第二步检查数据文件是否已存在 if [ -f ${DATA_FILE} ]; then echo [ERROR] Datafile ${DATA_FILE} already exists, exit. exit 1 fi # 第三步通过sqlplus创建表空间 sqlplus -S / as sysdba EOF CREATE TABLESPACE ${TBS_NAME} DATAFILE ${DATA_FILE} SIZE ${INIT_SIZE} AUTOEXTEND ON NEXT ${NEXT_SIZE} MAXSIZE ${MAX_SIZE}; EXIT; EOF脚本逻辑很简单但有一个细节值得注意第二步检查文件是否已存在。这个检查很多人会忽略结果在重复执行脚本时Oracle直接报“file already exists”或者更诡异的“ORA-01537: cannot add file ... file already part of tablespace”。加了这一步之后脚本会提前退出至少不至于把错误留给用户去猜。3.4 创建后的体检与监控建完表空间并不代表事情结束了。我的习惯是顺手做一遍“体检”确认新建表空间不会成为下一个隐患。体检分三步走先看空间使用率确保初始分配的空间和业务预期匹配SQL SELECT df.tablespace_name, df.bytes/1024/1024/1024 AS total_gb, ROUND(fs.free_bytes/1024/1024/1024, 2) AS free_gb FROM dba_data_files df, (SELECT tablespace_name, SUM(bytes) AS free_bytes FROM dba_free_space GROUP BY tablespace_name) fs WHERE df.tablespace_name fs.tablespace_name AND df.tablespace_name TBS_APP;再看自动扩展设置是否合理防止数据文件到达MAXSIZE后业务直接卡死SQL SELECT tablespace_name, file_name, autoextensible, maxbytes/1024/1024/1024 AS max_gb FROM dba_data_files WHERE tablespace_name TBS_APP;最后把新建表空间纳入日常监控脚本。最简单的做法是写一个定时任务每天检查所有表空间使用率超过85%就告警。告警机制越早介入越不容易出现“半夜三更表空间满了业务全部卡住”的被动局面。4. 常见问题与排查技巧实录4.1 目录一直存在为什么还是报“不存在”这是我最常被问到的问题。目录明明在文件系统ls也能看到但Oracle就是报No such file or directory。总结下来通常有四个容易被忽略的因素第一个是符号链接问题。很多环境会把数据目录软链到别处比如/u01是指向/data的软链。你在/u01/oradata下创建了文件但某个节点的软链断了或者软链指向的位置没挂载Oracle自然找不到。第二个是大小写问题。Linux文件系统区分大小写/u01/Oradata和/u01/oradata是两个完全不同的目录。这种问题在Windows环境不常见但在Linux和Unix环境很典型。第三个是NFS挂载问题。如果你把数据文件放在NFS共享目录上首先要确认NFS服务正常、所有节点都成功挂载。挂载失败时目录看起来空空的Oracle想写文件也没地方写表现就是找不到路径。可以用df -h查看挂载点用showmount -e nfs_server确认共享是否正常。第四个是ASM磁盘组没挂载。在ASM环境下如果磁盘组不是MOUNTED状态你执行建表空间时同样会报目录或路径相关的错误。检查方法很简单SQL SELECT name, state, type FROM v$asm_diskgroup;只要发现state不是MOUNTED先处理磁盘组再回来看建表空间的问题。这四个因素几乎覆盖了所有“目录明明存在但Oracle说没有”的场景。遇到这种问题时我建议老老实实按顺序排查先ls确认操作系统层面能看到再mount确认挂载状态再确认权限最后看ASM。多数情况下问题出在某个你没想到的节点或存储层级上。4.2 RAC环境表空间满了怎么处理搜索热度很高的另一个话题是“Oracle RAC表空间满了怎么办”。RAC环境里表空间满的表现和单机有些差异因为多个实例共享一套数据文件任何节点上的会话都可能突然报错。常见的报错有ORA-01653: unable to extend table SYS.TEST by 128 in tablespace TBS_APP ORA-01654: unable to extend index SYS.IDX_TEST by 128 in tablespace TBS_APP ORA-01631: max # extents (4096) reached in table SYS.TEST处理思路其实和单机一致但因为涉及多个实例和共享存储操作时要更谨慎。第一步先定位是不是真的表空间满了SQL SELECT tablespace_name, ROUND(SUM(bytes)/1024/1024/1024, 2) AS total_gb FROM dba_data_files GROUP BY tablespace_name; SQL SELECT tablespace_name, ROUND(SUM(bytes)/1024/1024/1024, 2) AS free_gb FROM dba_free_space GROUP BY tablespace_name;如果确认空闲空间接近0下一步就是扩容。扩容有三种常见方式我按推荐顺序说明第一种给现有表空间增加数据文件。适合smallfile表空间也适合想让文件分散到不同磁盘的场景SQL ALTER TABLESPACE tbs_app ADD DATAFILE /u01/oradata/orcl/tbs_app02.dbf SIZE 10G AUTOEXTEND ON NEXT 512M MAXSIZE 32G;第二种开启或调整自动扩展。如果数据文件本身就设了AUTOEXTEND可能是MAXSIZE设得太小。可以这样调整SQL ALTER DATABASE DATAFILE /u01/oradata/orcl/tbs_app01.dbf AUTOEXTEND ON NEXT 512M MAXSIZE 64G;第三种对于bigfile表空间直接RESIZE。因为bigfile表空间只有一个数据文件扩容就是把这个文件变大SQL ALTER TABLESPACE tbs_big RESIZE 100G;RAC环境下特别提醒一句如果是文件系统上的共享存储扩容操作必须在所有节点都能访问到该文件的前提下进行。最稳妥的做法是确认共享存储挂载无误后通过任意一个节点执行然后换到另一个节点查询验证。不要同时从两个节点对同一个数据文件做扩容操作这类并发操作容易引发锁和一致性异常。4.3 清理表空间的正确姿势表空间满了扩容是“治标”要想“治本”还得把闲置空间真正释放出来。这里我分享一套经过多次生产实践验证的清理顺序。第一步先清回收站。这是性价比最高的一步回收站里积压的已DROP对象可能占几十G甚至几百G一条SQL就能释放大量空间SQL PURGE DBA_RECYCLEBIN;或者只清理某个表空间下的回收站SQL PURGE TABLESPACE tbs_app;执行前确认回收站里的对象确实不需要恢复否则一旦PURGE就找不回来了。第二步找出占空间的大段。优先从应用表入手逐个排查哪些表、索引、LOB字段最占空间SQL SELECT owner, segment_name, segment_type, ROUND(bytes/1024/1024/1024, 2) AS size_gb FROM dba_segments WHERE tablespace_name TBS_APP ORDER BY bytes DESC FETCH FIRST 20 ROWS ONLY;第三步针对大对象做处理。如果是历史分区表优先考虑TRUNCATE或DROP过期分区如果是普通表但要保留数据可以用SHRINK SPACE或MOVE。两者各有优劣我整理了一个对比操作是否锁表是否移动段注意事项TRUNCATE/DROP 分区短暂锁删除数据确认历史数据可丢SHRINK SPACE锁表期间影响DML原地压缩需开启ROW MOVEMENTMOVE锁表且移动段重建段位置需要重建索引和约束SHRINK的操作方式是这样的SQL ALTER TABLE tbs_app.t_big ENABLE ROW MOVEMENT; SQL ALTER TABLE tbs_app.t_big SHRINK SPACE CASCADE;MOVE的方式则是SQL ALTER TABLE tbs_app.t_big MOVE TABLESPACE tbs_app; SQL ALTER INDEX tbs_app.idx_big REBUILD;注意MOVE之后索引会失效必须重建。有LOB字段的表MOVE默认不会搬LOB段需要用带LOB子句的语法这也是很多DBA踩坑的地方。第四步数据文件收缩。前面三步做完表空间内部可能出现大量空闲空间但数据文件本身还是那么大这时才适合做RESIZE。收缩前先确认文件尾部是空闲的否则会报ORA-03297。简单判断方法是查该数据文件内最后一个有数据的分区位置更省事的做法是直接尝试收缩如果报ORA-03297就得先对尾部的对象做MOVE或调整。SQL ALTER DATABASE DATAFILE /u01/oradata/orcl/tbs_app01.dbf RESIZE 12G;这里要特别提醒RESIZE只能把文件收缩到高水位以上一点如果文件里数据分布分散收缩效果可能不理想。先把碎片对象挪走再收缩成功率会高很多。清理表空间这件事最忌讳的是一上来就DROP表、DROP表空间。生产环境数据是无价的每一步操作前都要确认可回退、可恢复最好维护一套坑位清单把每次执行前和执行后的空间快照留下来便于回溯。我在实际运维中还有一个体会表空间满的问题90%是可以提前预防的。把监控做起来把自动扩展的MAXSIZE设合理把表空间规划成大而少而不是小而多能少掉一半以上的救火操作。如果你现在正被“目录不存在”这类问题困扰不妨按照我上面的方案先把OMF打开再把目录检查脚本挂上最后把清理流程存成自己的SOP。这些动作看着不起眼但它们带来的稳定性和省心程度绝对对得起你花掉的这一两个小时。
返回列表