☰
Oracle数据库日常运维指南:实例检查、空间监控、备份恢复与SQL优化
2026/10/12 1:15:18 网站建设 项目流程

简介:一份面向Oracle数据库运维人员的系统化维护教程,覆盖实例启停、日常巡检、RAC操作与紧急故障处理等内容。资源以1个PPT文件呈现,整体大小仅1.83MB,便于快速下载与翻阅。已有98人浏览学习,适合作为数据库入门与日常维护的参考。内容从实例启动的Nomount、Mount、Open三阶段与NORMAL、TRANSACTIONAL、IMMEDIATE、ABORT四种关闭模式讲起,详细说明各阶段检查要点与操作差异;随后展开数据库日志、性能、存储、安全等常规检查项,介绍企业管理器的管理功能,并针对RAC环境给出日常操作维护思路。此外,还涵盖数据库紧急故障恢复及alertSID.log、后台/用户跟踪文件等诊断文件的管理方法,有助于运维人员建立系统的维护框架并快速定位常见问题。

1. Oracle日常管理与维护:别等告警响了才想起来数据库还要人管

很多单位装完Oracle数据库后一年都不动它,直到某天凌晨磁盘告警、业务反馈连不上库,DBA才连夜爬起来处理。我见过太多所谓“日常管理”,最后都变成了“故障应急”。Oracle日常管理与维护的核心,是把实例和监听状态、表空间水位、备份可恢复性、SQL性能变化这四类东西,变成每天能验证的例行动作,而不是让数据库像黑匣子一样跑着。这篇笔记写给要自己扛库的运维、DBA和半路接手的开发,按实例、备份、性能、避坑这条线往下走,每一段都能直接抄到命令行。

2. 实例与监听:用三条命令判断数据库今天是否健康

数据库能不能对外服务,第一道关口是实例和监听。实例代表Oracle内存和后台进程加起来的那套运行体系,监听则是客户端接入的入口。日常维护不需要把几百个视图全查一遍,先确认三件事:实例状态、告警日志里有没有ORA-、监听能不能连。

2.1 检查实例状态与告警日志:sqlplus 加 tail 就够了

以root切到oracle用户,用操作系统认证进数据库:

sqlplus / as sysdba

进去以后先看实例和数据库状态:

SELECT instance_name, status, database_status, startup_time FROM v$instance; SELECT name, open_mode FROM v$database;

正常情况status是OPEN,database_status是ACTIVE,open_mode是READ WRITE。startup_time能告诉你数据库是不是被人悄悄重启过。如果status是STARTED或MOUNTED,说明实例还没完全打开,通常是崩溃恢复过程中的状态。接着直接看告警日志:

tail -200 $ORACLE_BASE/diag/rdbms/<dbname>/<SID>/trace/alert_<SID>.log

dbname是数据库名,SID是实例名,路径在12c之后都走ADR统一管理,不用再满世界找udump/bdump。想看准确路径,查v$diag_info视图里DIAG_TRACE的值。告警日志里重点搜ORA-、ORA-600、ORA-07445以及“space”相关字样,这类通常是内部错误或者表空间写满了。数据库如果跑在Linux上,还要顺手确认开机自启动配置,改/etc/oratab把最后一项从N改成Y,再配置dbstart和dbstop对应脚本。很多人忘了这个,机房断电重启后应用全连不上,才回来翻这个文件。如果数据库用的是ASM存储,日常还要看一眼磁盘组剩余空间,进入ASM实例可以执行sqlplus / as sysasm,或者直接asmcmd lsdg查看使用率。记住ASM实例里没有业务数据,它只负责管理磁盘,不能当普通实例来连。

2.2 监听服务无法启动:从 tnsping 到 listener.log 的排查顺序

监听是单独的一套进程,跟实例不绑定。实例挂了监听可能还在,反过来监听挂了实例照跑但客户端连不进来。很多同事一遇到连不上就重启数据库,其实监听才是元凶。排查顺序我一般固定为tnsping、lsnrctl、listener日志、端口这四步:

tnsping orcl lsnrctl status lsnrctl start tail -100 $ORACLE_BASE/diag/tnslsnr/$(hostname)/listener/trace/log.xml netstat -an | grep 1521

tnsping通说明本机的tnsnames.ora解析没问题,但不代表监听能干活,必须lsnrctl status看实际状态。监听启动报错最常见的是TNS-12541和TNS-01189,一般是有残留进程占着端口,或者上一次异常退出留下的pid文件没清掉。这时候先lsnrctl stop,再检查有没有LISTENER进程残留,kill掉后重新lsnrctl start。不要一上来就改listener.ora,90%的情况是进程残留,不是配置错。日志路径也分版本,10g在ORACLE_HOME/network/log,11g之后进了ADR,路径里会带主机名,用$(hostname)拼接更稳。另外Windows上监听服务起不来,先去服务管理器看“OracleOraDb...TNSListener”这个服务的登录身份和依赖关系,常见坑是服务密码过期或者Oracle主目录环境变量指向了旧路径。

2.3 listener.log 疯长:10g 到 19c 的监听日志清理办法

监听日志是另一个日常维护重点。默认情况下listener.log把所有连接尝试都写进去,日志增长快,高峰期几分钟就能写上几百MB,磁盘被它占满的案例非常多。注意对Oracle 10g、11g和12c之后的处理姿势不一样。

10g里监听日志在$ORACLE_HOME/network/log,12c以后在ADR的listener/trace目录,而且日志格式变成XML。清理不能直接rm,因为监听进程持有文件句柄,直接删了空间不释放,还会导致后续写日志报错。我常用的轮转方式是保留最近一份日志,清空原文件,再让监听重新打开文件:

LOG_DIR=$ORACLE_BASE/diag/tnslsnr/$(hostname)/listener/trace DT=$(date +%Y%m%d) mv "$LOG_DIR/listener.log" "$LOG_DIR/listener_$DT.log" > "$LOG_DIR/listener.log" lsnrctl reload

reload会通知监听重新打开日志文件,比stop/start平滑,正在跑的连接不会断。配合crontab每天凌晨执行一次,日志就按天归档了。12c以后也可以直接改参数降低连接日志的详细程度,比如设置日志级别为OFF来彻底不写,但生产环境不建议关,否则排查问题没有依据。这类日志里也容易混入恶意扫描的连接记录,定期归档既保磁盘也保留排查依据,是日常管理里性价比很高的一件事。

3. 表空间与备份恢复:空间管理和后悔药都不能缺

磁盘满了是数据库最常见的“慢性死亡”方式,所以空间管理排第二。备份恢复则是最后一道后悔药,很多团队只备份不恢复演练,出了事才发现备份根本不能用。这一章把两条线一起讲清楚。

3.1 表空间使用率:一条 SQL 把所有数据文件看明白

日常巡检里,我至少每天看一次表空间水位。最顺手的是这条:

SELECT d.tablespace_name, ROUND(SUM(d.bytes)/1024/1024/1024, 2) total_gb, ROUND(NVL(SUM(f.bytes),0)/1024/1024/1024, 2) free_gb, ROUND((SUM(d.bytes) - NVL(SUM(f.bytes),0)) / SUM(d.bytes) * 100, 2) used_pct FROM dba_data_files d LEFT JOIN dba_free_space f ON d.file_id = f.file_id GROUP BY d.tablespace_name ORDER BY used_pct DESC;

dba_data_files统计的是分配给数据文件的总大小,dba_free_space按文件ID关联出剩余空间。used_pct超过85%就要关注,超过90%建议立即扩容或清理。注意自动扩展这个参数别迷信,很多表空间虽然autoextend on,但maxsize设了上限,照样会满。查maxsize也简单,把dba_data_files里的maxbytes字段带出来就行。另外,删除大表数据后表空间使用率可能一点没降,因为DELETE只是打标记,段的空间不还给文件系统。要彻底释放要么TRUNCATE,要么用ALTER TABLE ... SHRINK SPACE,后者要注意在业务低峰执行。临时表空间暴涨也不要忽略,查v$temp_space_header能看到临时文件水位,排序和临时段写入了太多数据时它也会爆。

3.2 RMAN 备份策略:保留策略和归档日志怎么配合

RMAN是Oracle默认的备份恢复工具,日常维护里最难的不是敲命令,是定策略。核心就是回答两个问题:备份留几天,归档日志怎么配。

rman target / CONFIGURE RETENTION POLICY TO RECOVERY WINDOW OF 7 DAYS; CONFIGURE CONTROLFILE AUTOBACKUP ON; BACKUP DATABASE PLUS ARCHIVELOG DELETE INPUT;

恢复窗口7天,意思是可以把数据库恢复到7天内的任意时间点。PLUS ARCHIVELOG表示备份数据库的同时备份归档日志,并且DELETE INPUT会在备份完成后删掉已备份的归档,这样归档目录不容易爆。只备份数据库不备份归档,恢复到故障点会缺日志,这是最常见的血泪教训。库比较大的时候,全备放周日晚,周一到周六做增量:

BACKUP INCREMENTAL LEVEL 0 DATABASE; BACKUP INCREMENTAL LEVEL 1 CUMULATIVE DATABASE;

Level 0相当于全备基线,Level 1累积备份只包含自上次Level 0以来的变化,恢复时需要先还原Level 0再叠Level 1。备份不是跑完就完,还要定期用CROSSCHECK核对备份集,因为磁盘上的备份文件可能被手动清理或迁移,RMAN里的元数据早就对不上了。我一般加一条定时任务,每周做一次CROSSCHECK和DELETE OBSOLETE,避免备份集变成一堆僵尸记录。

3.3 恢复演练:全库恢复、表空间恢复、单表恢复

备份做得再勤,不演练等于没有。日常维护里最值钱的时间,就是用来做恢复演练的时间。按风险从低到高,通常练三种恢复。

全库恢复,适合彻底崩溃场景:

# 第一阶段:启动到 mount sqlplus / as sysdba <<EOF STARTUP MOUNT; EOF # 第二阶段:在 RMAN 中还原并恢复 rman target / <<EOF RESTORE DATABASE; RECOVER DATABASE; EOF # 第三阶段:打开数据库 sqlplus / as sysdba <<EOF ALTER DATABASE OPEN; EOF

表空间恢复,适用某个数据文件损坏,比如磁盘坏道导致单个表空间文件损坏:

# 1. 表空间置为离线 sqlplus / as sysdba <<EOF ALTER TABLESPACE users OFFLINE IMMEDIATE; EOF # 2. 在 RMAN 中还原并恢复 rman target / <<EOF RESTORE TABLESPACE users; RECOVER TABLESPACE users; EOF # 3. 表空间重新上线 sqlplus / as sysdba <<EOF ALTER TABLESPACE users ONLINE; EOF

单表恢复,最常用的是闪回,比如业务误删了一张表的数据:

FLASHBACK TABLE t TO TIMESTAMP TO_TIMESTAMP('2024-01-01 10:00:00','YYYY-MM-DD HH24:MI:SS');

闪回依赖undo空间,undo_retention太短或者表结构在误删后有DDL变更,闪回会失败。这时只能做表空间时间点恢复,或者从备份里挖出这张表再导入。还有一种场景是误TRUNCATE,闪回表救不了,只能靠闪回数据库或者RMAN恢复,所以TRUNCATE前一定仔细确认。恢复演练不能只在一个库里玩,要拿测试环境定期练,把关键步骤写成操作卡,真出事时照着卡来,不靠临场回忆。

4. 性能巡检与 SQL 优化:日常维护里翻车最多的一环

日常维护做完健康检查,剩下的时间基本都在跟SQL性能较劲。Oracle SQL性能优化的难点不是看执行计划,而是判断性能是“今天突然差”还是“一直就那样”。

4.1 AWR/ADDM 报告:先看结论再看图

AWR报告相当于Oracle自带的体检报告,ADDM则是直接给你诊断建议。很多人拿到几十页报告从头翻到尾,最后什么都没记住。我一般只盯几个区域:Top 10 Foreground Events、SQL ordered by Elapsed Time、Segment Statistics。生成报告用脚本就行:

-- 在 SQL*Plus 中执行 @?/rdbms/admin/awrrpt.sql @?/rdbms/admin/addmrpt.sql

执行后它会要你选快照起始和结束ID,一般选最近一天业务高峰前后两个快照。如果想主动打个快照:

EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT();

AWR快照默认每小时生成一个,保留8天,这两个参数在DBMS_WORKLOAD_REPOSITORY里都能调整。AWR里“Top 10 Foreground Events”如果看到db file sequential read或者log file sync排在前面,说明等待事件主要集中在IO或提交频率上,从这两条线继续往下查准没错。ADDM则会给一句人话,比如“等待SQL的缓冲池命中率偏低”,直接按它的建议调即可,别把AWR当黑匣子逐页啃。

4.2 执行计划为什么变:统计信息、绑定变量与分页查询

日常维护里最尴尬的是:代码没动,SQL突然慢了。十有八九是执行计划变了,触发原因就那么几个:统计信息过期、绑定变量窥探、数据分布偏移。先看执行计划:

EXPLAIN PLAN FOR SELECT * FROM users WHERE create_date > SYSDATE - 7; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

执行计划里如果看到全表扫描或索引跳跃扫描,而表数据量很大,第一反应是统计信息太旧。补一下:

EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT','USERS');

DBMS_STATS会重新收集表和列的基数、直方图,让CBO重新算代价。注意生产环境收集统计信息也要错峰,I/O密集时跑会拖慢业务。还有一类是绑定变量在第一次调用时被“窥视”到特定值,后面所有值都按那个值的执行计划走,这叫绑定变量窥探,解决思路是把直方图做好或者用自适应游标。说到分页查询,Oracle经典的写法是ROWNUM嵌套:

SELECT * FROM ( SELECT t.*, ROWNUM rn FROM (SELECT * FROM users ORDER BY user_id) t WHERE ROWNUM <= 40 ) WHERE rn > 20;

深分页时这条会越来越慢,因为内层排序要建完整结果集。12c以后可以用OFFSET FETCH,但要谨慎它内部实现;更快的做法是把分页改成基于上一页最后一个值的游标分页。还有个容易被问到的问题:视图上能不能加索引?不能。视图本身不存数据,要加速视图查询只能优化视图内部SQL,或者把视图改成物化视图。连着看执行计划、统计信息、分页写法,这套下来才算把SQL性能巡检闭环了。

4.3 存储过程用于巡检:一个表空间监控脚本的演进

巡检如果每次敲一遍SQL,早晚有人漏查。更稳的做法是把规则固化成一个存储过程,定时调用。比如把上面表空间使用率做成一个PL/SQL存储过程:

CREATE OR REPLACE PROCEDURE p_check_tablespace AS v_used_pct NUMBER; BEGIN FOR r IN (SELECT tablespace_name, SUM(bytes) total_bytes FROM dba_data_files GROUP BY tablespace_name) LOOP SELECT NVL(SUM(bytes),0) INTO v_used_pct FROM dba_free_space WHERE tablespace_name = r.tablespace_name; v_used_pct := (1 - v_used_pct / r.total_bytes) * 100; IF v_used_pct > 90 THEN DBMS_OUTPUT.PUT_LINE(r.tablespace_name || ' usage ' || v_used_pct || '%'); -- 生产环境这里换成 UTL_MAIL 发邮件,或写入巡检日志表 END IF; END LOOP; END p_check_tablespace;

存储过程的好处是检查逻辑统一,权限好管控,后续接Python连接Oracle做可视化时,直接查存储过程写入的巡检日志表就行。PL/SQL里如果需要变长数组,可以用VARRAY或ASSOCIATIVE ARRAY,但巡检这类轻量逻辑别用太重。

调用方式用DBMS_SCHEDULER比老式DBMS_JOB更灵活:

BEGIN DBMS_SCHEDULER.CREATE_JOB( job_name => 'JOB_CHECK_TBS', job_type => 'PLSQL_BLOCK', job_action => 'BEGIN p_check_tablespace; END;', start_date => SYSTIMESTAMP, repeat_interval => 'FREQ=DAILY; BYHOUR=8', enabled => TRUE ); END;

repeat_interval里的FREQ和BYHOUR定义频率,这里表示每天早上8点跑一次。改频率就改这个字符串,不用重新建job。所有巡检逻辑都按这个套路往DBMS_SCHEDULER里塞,Oracle实例状态、监听状态、备份状态都能自动化。Python连接Oracle主要是后面做展示层,真正让巡检少出人命的,是这一层调度。

5. 常见问题避坑:监听日志、ORA-01428 与删除不干净

日常维护里有一批问题不是不会处理,是每次都踩同一个坑。我按现象、原因、解决三步把高频问题列出来,方便你直接对照。

5.1 监听服务启动失败的两类现象与处理顺序

现象一:lsnrctl start执行后报TNS-12541/TNS-01189,监听起不来。原因:上一次Oracle异常退出,Listener进程还残留在内存,或者pid文件没清理。解决:先lsnrctl stop忽略报错,然后ps -ef | grep tnslsnr看残留进程,kill掉,再lsnrctl start。如果端口被其他程序占用,netstat -an | grep 1521能看到是谁占的。

现象二:tnsping能通,但应用还是报无法连接。原因:监听起来了,但实例没有注册到监听,数据库启动后动态注册需要几秒钟,如果SERVICE_NAME配置不对就一直不注册。解决:在监听里执行lsnrctl services,看看有没有对应服务;再回数据库执行ALTER SYSTEM REGISTER强制注册。别急着重启监听,很多时候service配置里的全局数据库名和实例名不一致,重启也白搭。

5.2 ORA-01428:参数越界不只在日期函数里

现象:某天跑一条SQL突然报ORA-01428: argument x is out of range,常见于TRUNC(SYSDATE)这类日期函数传入了一个超出范围的数字,比如月份传了13,或者天数传了32。

原因:Oracle函数对参数有严格定义域,参数越界就抛这个错。还有不少人写WHERE时直接用两个日期相减,再拿结果跟一个天数比较,天数写大了也会触发。

解决:先定位是哪条SQL、哪个参数越界。日期处理不要拼裸数字,用TO_DATE加格式掩码,例如TO_DATE('2024-02-30','YYYY-MM-DD')这种一看就是无效日期。TRUNC(SYSDATE)本身没问题,问题常在它周围的表达式。顺便提醒,dual表只有一行一列,做SELECT NVL(MAX(...),0)之类没问题,别把大结果集往dual上堆,误用的人不在少数。

5.3 12c 删除不干净:重装失败时的清理思路

现象:Oracle 12c卸载后重装,要么配置助手中途报错,要么监听服务起不来,要么安装界面提示“实例已存在”。

原因:卸载时只删了ORACLE_HOME目录,服务、注册表、环境变量和启动项没清干净。Windows下尤其明显,服务里还能看到OracleOraDB12Home1_...的服务名。

解决:以管理员身份逐项清理。先停掉所有Oracle服务,在命令行里用sc delete逐个删服务;再打开注册表,删除HKEY_LOCAL_MACHINE\SOFTWARE\Oracle键;还有HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services下Oracle开头和ORA开头的服务键也要清。最后把oracle用户的环境变量ORACLE_HOME、ORACLE_SID、PATH里的Oracle路径全部删掉,检查启动项和计划任务里有没有残留。重装前再确认一下端口1521没被占用,这一步做完基本就能干干净净装上了。

另一个跟删除相关的坑:业务让“删掉一张表的部分数据”,你用DELETE删完,结果表空间磁盘空间没降下来。原因是高水位线还在,段空间没有收缩。解决方式是如果确认数据不需要,用TRUNCATE;如果需要保留部分行,就用ALTER TABLE ... SHRINK SPACE,前提是表没有禁用行移动。这类误用DELETE导致空间不释放的翻车现场,几乎每个月都能见到。

6. 进阶:把巡检攒成一个可复用的 shell 检查清单

前面的内容分开看都是点,最后把它们串成一条线:一个每天早上自动跑一遍的shell巡检脚本。这个脚本不需要复杂框架,能输出结果、能定位问题就行。

6.1 脚本骨架:一次巡检该查哪些东西

#!/bin/bash export ORACLE_SID=orcl export ORACLE_HOME=/u01/app/oracle/product/19.0.0/dbhome_1 export PATH=$ORACLE_HOME/bin:$PATH LOG=/var/log/oracle_daily_$(date +%F).log sqlplus -s / as sysdba <<EOF > "$LOG" SET PAGESIZE 100 SELECT instance_name, status FROM v\$instance; SELECT tablespace_name, ROUND((SUM(bytes) - NVL(SUM(free),0)) / SUM(bytes) * 100, 2) used_pct FROM (SELECT tablespace_name, bytes, 0 free FROM dba_data_files UNION ALL SELECT tablespace_name, 0 bytes, bytes free FROM dba_free_space) t GROUP BY tablespace_name HAVING used_pct > 90; EOF if grep -E "ORA-|TNS-" "$LOG"; then echo "【异常】巡检中发现ORA或TNS错误" else echo "【正常】巡检完成" fi

脚本里v$instance必须写成v$instance,否则会被shell当成变量吞掉。used_pct那段用UNION ALL把已使用和空闲空间按表空间合并,再算使用率,比单独JOIN更不容易漏。grep那行会打印异常行,这是最简的告警方式。生产环境可以再用mailx把LOG发到值班邮箱,或者把告警行写入业务监控平台。如果是等保要求比较严的环境,建议在脚本里加AUDIT或者记录操作日志,历史输出保留半年,这些都有对应的等保命令和审计配置,别等到检查时才补。

6.2 定时执行与结果验证:crontab、日志与告警

# crontab -e,每天上午8点执行 0 8 * * * /home/oracle/bin/ora_daily_check.sh >> /var/log/oracle_cron.log 2>&1

执行完别直接走人,要看三样东西:一是cron执行记录,确认脚本真的跑了;二是当天的ora_daily_日期.log,看看内容里有没有HAVING筛选出的超阈值表空间;三是手动跑一遍脚本,确认sqlplus没因为环境变量问题静默失败。我自己的习惯是每周一早上一来就看上周的巡检日志统计,而不是只看当天。

现在回顾一下这几年的维护经验,最深的教训是:巡检脚本能发现90%的问题,但剩下10%要靠恢复演练兜底。以前我光写脚本不看结果,直到一次真实恢复时发现归档日志少了一段,才知道自动化的前提是结果可验证。后来给自己定了死规矩,脚本跑完必须人工扫一眼关键输出,每月最后一个周五做一次RMAN恢复演练。这套流程坚持下来,数据库出大问题的次数确实少了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询