我们的文章会在微信公众号Oracle恢复实录和博客网站(www.htz.pw)同步更新 ,欢迎关注收藏。也欢迎大家转载,但请在文章开始处标注文章出处,谢谢!

由于博客中包含大量代码,建议通过网页浏览以获得更好的阅读体验。

背景介绍

在Oracle数据库运维过程中,合理配置重做日志(Redo Log)文件的大小和数量是非常重要的。不合适的重做日志配置可能会导致以下问题:

  1. 日志切换过于频繁,影响数据库性能
  2. 日志文件太小,导致归档速度跟不上
  3. 日志组数量不足,影响数据库可用性

今天给大家分享一个实用的脚本工具,可以帮助DBA快速调整重做日志文件的配置。

脚本功能介绍

这个脚本(db_add_logfile.sql)主要实现以下功能:

  1. 自动添加指定大小的重做日志文件组
  2. 支持指定每个线程的日志组数量
  3. 自动清理小于指定大小的旧日志文件
  4. 支持ASM和文件系统两种存储方式
  5. 支持RAC环境
  6. 支持归档和非归档模式

使用方法

脚本接受三个参数:

@db_add_logfile.sql [日志文件大小] [每线程日志组数量] [日志文件路径]

参数说明:

  • 参数1:日志文件大小(默认2G)
  • 参数2:每个线程的日志组总数(默认7)
  • 参数3:日志文件路径(默认使用现有日志组的路径)

使用示例:

@db_add_logfile.sql 2 8 +DATA_01

脚本特点

  1. 智能路径处理

    • 自动识别ASM和文件系统路径
    • ASM环境下自动检查磁盘组是否存在
    • 支持Windows和Linux文件系统路径格式
  2. 安全性保障

    • 添加新日志组前检查路径有效性
    • 删除旧日志组时自动检查状态
    • 包含完善的错误处理机制
  3. 兼容性

    • 支持Oracle RAC环境
    • 支持归档和非归档模式
    • 自动处理多线程情况

实现原理

  1. 路径类型判断
WHEN REGEXP_REPLACE (MEMBER, '[^\+]', '') = '+' THEN 'ASM'
WHEN SUBSTR (x.MEMBER, 1, REGEXP_INSTR (x.MEMBER, '[/]', 1, 2) - 1) = '/dev' THEN '/dev'
ELSE 'FS'
  1. 日志组状态处理
WHILE i_group_status IN ('ACTIVE', 'CURRENT') LOOP
EXECUTE IMMEDIATE i_sql_arch2;
SELECT status INTO i_group_status FROM v$log
WHERE group# = i_delete_group.group#;
IF i_group_status != 'INACTIVE' THEN
DBMS_LOCK.SLEEP (2);
END IF;
END LOOP;

完整的代码

当前发布时的版本如下,如要获得最新版本,请公众号回复db_add_logfile,或者直接连接我。

/* Formatted on 2025/6/9 23:00:19 (QP5 v5.300) */
-- File Name : db_add_logfile.sql
-- Purpose : Add redo log file groups to the database, specify log group number,
-- specify log file size, auto delete log files smaller than specified size
-- @db_add_logfile.sql (press enter)
-- @db_add_logfile.sql 2 8 +DATA_01
-- Date : 2016/05/19
-- weixin:18081072613
-- http://www.htz.pw
-- 20161129 Added path input, if path is not specified, use the path of existing log groups.
-- 20161129 Added support for non-archive mode and RAC, in non-archive mode, only display message for current REDO.
-- 20250609 Enhanced functionality, added error handling
-- 20250610 重构整个代码,并修复asm磁盘组路径传入忽略+的导致的报错,增加磁盘组是否存在的检查
SET LINES 200
SET PAGES 1000 HEADING ON VERIFY OFF SERVEROUTPUT ON
PRO
PRO Parameter 1:
PRO log file size (default 2g)
PRO
PRO Parameter 2:
PRO total group number by thread (default 7)
PRO
PRO Parameter 3:
PRO log file path name(for +DG_DATA) (default old path name)
PRO
PRO DECLARE
path_type VARCHAR2 (200);
path_name VARCHAR2 (200);
i_group_current NUMBER;
i_logfile_size NUMBER;
i_group_number NUMBER;
i_log_number NUMBER;
i_group_name NUMBER;
i_instance_id NUMBER;
i_sql VARCHAR2 (200);
i_sql_arch VARCHAR2 (200) := 'alter system switch logfile';
i_sql_arch2 VARCHAR2 (200) := 'alter system archive log current';
i_group_status VARCHAR2 (200);
i_logfile_name VARCHAR2 (200);
i_log_mode VARCHAR2 (200); BEGIN
DECLARE
PROCEDURE drop_logfile_group (p_group_no IN NUMBER)
IS
v_sql VARCHAR2 (200);
BEGIN
v_sql := 'alter database drop logfile group ' || p_group_no;
DBMS_OUTPUT.put_line (v_sql); EXECUTE IMMEDIATE v_sql;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (
'Warning: Unknown error occurred when dropping log group '
|| p_group_no
|| ': '
|| SQLERRM);
DBMS_OUTPUT.put_line ('Continue processing next log group...');
END;
BEGIN
SELECT TO_NUMBER (NVL ('&1', 2) * 1024 * 1024 * 1024)
INTO i_logfile_size
FROM DUAL; SELECT TO_NUMBER (NVL ('&2', 6)) INTO i_group_number FROM DUAL; SELECT NVL ('&3', 'DEFAULT') INTO path_name FROM DUAL; SELECT log_mode INTO i_log_mode FROM v$database; SELECT instance_number INTO i_instance_id FROM v$instance; IF path_name = 'DEFAULT'
THEN
SELECT CASE
WHEN REGEXP_REPLACE (MEMBER, '[^\+]', '') = '+'
THEN
'ASM'
WHEN SUBSTR (x.MEMBER,
1,
REGEXP_INSTR (x.MEMBER,
'[/]',
1,
2)
- 1) = '/dev'
THEN
'/dev'
ELSE
'FS'
END
AS path_type,
CASE
WHEN REGEXP_REPLACE (MEMBER, '[^\+]', '') = '+'
THEN
SUBSTR (x.MEMBER,
1,
REGEXP_INSTR (x.MEMBER,
'[/]',
1,
1)
- 1)
ELSE
SUBSTR (
x.MEMBER,
1,
REGEXP_INSTR (x.MEMBER,
'[/]',
1,
REGEXP_COUNT (x.MEMBER, '[/]')))
END
AS name
INTO path_type, path_name
FROM v$logfile x
WHERE ROWNUM = 1;
ELSE
SELECT CASE
WHEN REGEXP_REPLACE (path_name, '[^\+]', '') = '+'
THEN
'ASM'
WHEN SUBSTR (path_name,
1,
REGEXP_INSTR (path_name,
'[/]',
1,
2)
- 1) = '/dev'
THEN
'/dev'
WHEN (REGEXP_LIKE(path_name, '^[A-Za-z]:\\.*$') OR
REGEXP_LIKE(path_name, '^/.*$'))
THEN
'FS'
ELSE
'ERROR'
END
AS path_type
INTO path_type
FROM DUAL x
WHERE ROWNUM = 1;
END IF;
IF path_type = 'ERROR' THEN
DBMS_OUTPUT.put_line('Error: The specified filesystem path does not exist or has invalid format');
RETURN;
END IF;
-- 如果是ASM路径,检查磁盘组是否存在
IF path_type = 'ASM' THEN
DECLARE
v_diskgroup_exists NUMBER;
v_diskgroup_name VARCHAR2(30);
BEGIN
-- 提取磁盘组名称 (去掉+号)
v_diskgroup_name := SUBSTR(path_name, 2, INSTR(path_name, '/') - 2); -- 检查磁盘组是否存在
SELECT COUNT(*)
INTO v_diskgroup_exists
FROM v$asm_diskgroup
WHERE name = v_diskgroup_name; IF v_diskgroup_exists = 0 THEN
DBMS_OUTPUT.put_line('Error: ASM diskgroup ' || v_diskgroup_name || ' does not exist');
RETURN;
END IF;
END;
END IF; SELECT (MAX (group#) + 1)
INTO i_group_name
FROM v$logfile; FOR c_thread IN (SELECT DISTINCT thread#
FROM v$log)
LOOP
SELECT COUNT (*)
INTO i_group_current
FROM v$log
WHERE thread# = c_thread.thread# AND bytes >= i_logfile_size; WHILE i_group_current < i_group_number
LOOP
IF path_type = 'ASM'
THEN
i_sql :=
'alter database add logfile thread '
|| c_thread.thread#
|| ' '
|| CHR (39)
|| path_name
|| CHR (39)
|| ' size '
|| i_logfile_size;
ELSIF path_type = 'FS'
THEN
i_logfile_name :=
path_name || 'redo' || i_group_name || '.log'; SELECT COUNT (*)
INTO i_log_number
FROM v$logfile
WHERE MEMBER = i_logfile_name; WHILE i_log_number > 0
LOOP
i_group_name := i_group_name + 1;
i_logfile_name :=
path_name || 'redo' || i_group_name || '.log'; SELECT COUNT (*)
INTO i_log_number
FROM v$logfile
WHERE MEMBER = i_logfile_name;
END LOOP; i_sql :=
'alter database add logfile thread '
|| c_thread.thread#
|| ' '
|| CHR (39)
|| path_name
|| 'redo'
|| i_group_name
|| '.log'
|| CHR (39)
|| ' size '
|| i_logfile_size;
END IF; DBMS_OUTPUT.put_line (i_sql); EXECUTE IMMEDIATE i_sql; i_group_current := i_group_current + 1;
i_group_name := i_group_name + 1;
END LOOP; FOR i_delete_group
IN (SELECT group#, THREAD#
FROM v$log
WHERE thread# = c_thread.thread#
AND BYTES < i_logfile_size)
LOOP
SELECT status
INTO i_group_status
FROM v$log
WHERE group# = i_delete_group.group#; IF i_log_mode = 'ARCHIVELOG'
THEN
WHILE i_group_status IN ('ACTIVE', 'CURRENT')
LOOP
EXECUTE IMMEDIATE i_sql_arch2; SELECT status
INTO i_group_status
FROM v$log
WHERE group# = i_delete_group.group#; IF i_group_status != 'INACTIVE'
THEN
DBMS_LOCK.SLEEP (2);
END IF;
END LOOP; i_sql :=
'alter database drop logfile group '
|| i_delete_group.group#; DBMS_OUTPUT.put_line (i_sql); EXECUTE IMMEDIATE i_sql;
ELSE
IF i_instance_id = c_thread.thread#
THEN
WHILE i_group_status IN ('ACTIVE', 'CURRENT')
LOOP
EXECUTE IMMEDIATE i_sql_arch; SELECT status
INTO i_group_status
FROM v$log
WHERE group# = i_delete_group.group#; IF i_group_status != 'INACTIVE'
THEN
DBMS_LOCK.SLEEP (2);
END IF;
END LOOP; drop_logfile_group (i_delete_group.group#);
ELSE
IF i_group_status IN ('ACTIVE', 'CURRENT')
THEN
DBMS_OUTPUT.put_line (
'manual exec : alter database drop logfile group '
|| i_delete_group.group#
|| ' on '
|| c_thread.thread#);
ELSE
drop_logfile_group (i_delete_group.group#);
END IF;
END IF;
END IF;
END LOOP;
END LOOP;
END;
END;
/

使用注意事项

  1. 执行脚本前需要具备足够的权限
  2. 建议在业务低峰期执行
  3. ASM环境下需要确保磁盘组有足够空间
  4. RAC环境中注意观察所有节点的日志切换情况

更新历史

  • 2025/06/10:重构代码,修复ASM磁盘组路径问题,增加磁盘组存在性检查
  • 2025/06/09:增强功能,添加错误处理
  • 2016/11/29:增加路径输入支持,增加非归档模式和RAC支持
  • 2016/05/19:初始版本发布

总结

这个脚本工具可以帮助DBA快速调整Oracle数据库的重做日志配置,提高数据库的可维护性和性能。它的智能判断和安全机制可以让DBA放心使用,是一个值得收藏的运维工具。

以上就是这个Oracle DBA工具的详细介绍。如果您在使用过程中遇到任何问题,欢迎留言交流!

------------------作者介绍-----------------------

姓名:黄廷忠

现就职:Oracle中国高级服务团队

曾就职:OceanBase、云和恩墨、东方龙马等

电话、微信、QQ:18081072613


Oracle DBA必备工具:自动调整重做日志文件大小和数量的更多相关文章

  1. 修改oracle重做日志文件大小

    创建3个新的日志组 SQL> ALTER DATABASE ADD LOGFILE GROUP 4 ('/u01/app/oracle/oradata/orcl/redo06.log') SIZ ...

  2. Oracle 联机重做日志文件(ONLINE LOG FILE)

    --========================================= -- Oracle 联机重做日志文件(ONLINE LOG FILE) --================== ...

  3. Oracle DBA面试突击题

    一份ORACLE DBA面试题 一:SQL tuning 类 1:列举几种表连接方式 答: Oracle的多表连接算法有Nest Loop.Sort Merge和Hash Join三大类,每一类又可以 ...

  4. InnoDB存储引擎的表空间文件,重做日志文件

    存储引擎文件:因为MySQL表存储引擎的关系,每个存储引擎都会有自己的文件来保存各种数据.这些存储引擎真正存储了数据和索引等数据. 表空间文件 InnoDB存储引擎在存储设计上模仿了Oracle,将存 ...

  5. 2. 更改InnoDB redo日志文件的数量或大小

    2. 更改InnoDB redo日志文件的数量或大小 要更改InnoDB 重做日志文件的数量或大小,请执行以下步骤: 1)停止MySQL服务器,确保正常关闭且没有错误发生 2) 编辑my.cnf以更改 ...

  6. Oracle Logminer 分析重做日志RedoLog和归档日志ArchiveLog

    在实际开发过程中,有时我们很有可能需要某个表的操作痕迹,或通过记录的SQL语句进行有目的性的数据恢复(此时POINT-IN-TIME恢复已经满足不了更细的粒度).或仅仅是查看: 据说Oracle8i之 ...

  7. 初识oracle重做日志文件

    转自 http://blog.csdn.net/indexman/article/details/7746948 以下易容翻译自oracle dba官方文档,不足之处还望指出. 管理重做日志文件 学习 ...

  8. ORACLE - 管理重做日志文件

    ORACLE重做日志文件用于在数据库崩溃等情况下用于恢复数据,默认情况下为三个文件redo01.log/redo02.log/redo03.log,文件组循环使用,在录入与更新操作比较多的应用中,日志 ...

  9. ORACLE归档日志比联机重做日志小很多的情况总结

    ORACLE归档日志比联机重做日志小很多的情况   前几天一网友在群里反馈他遇到归档日志比联机重做日志(redo log)小很多的情况,个人第一次遇到这种情况,非常感兴趣,于是在一番交流沟通后,终于弄 ...

  10. Oracle重做日志REDO

    什么是重做? 重做日志包含所有数据产生的历史改变记录. 重做日志目的是保证数据的安全,如果数据因特殊原因没有写到磁盘上,可以通过重做日志来恢复. 重做日志文件通常用于 恢复(实例恢复和介质恢复) 日志 ...

随机推荐

  1. 使用react-native-drawer,跟着官网配置仍报错,Error: [Reanimated] `valueUnpacker` is not a worklet, js engine: hermes

    在使用react-native-drawer组件时,编译项目报错 试了许多的方法,最后通过在一篇博客中找到解决方法https://blog.csdn.net/lxyoucan/article/deta ...

  2. 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!

    前言 今天大姚给大家分享 3 个 .NET 开源.免费的文件压缩处理库,希望可以快速帮助同学们实现文件压缩和解压功能! SharpCompress SharpCompress 是一个基于 C# 编写的 ...

  3. 『Plotly实战指南』--饼图绘制基础篇

    在数据可视化的世界里,饼图是一种直观且广泛使用的图表类型. 它能够将数据各个部分占整体的比例关系清晰地展现出来,适用于诸如市场占有率分析.调查结果分布.预算分配等多个领域. 饼图以扇形面积比例直观展示 ...

  4. 【Ubuntu】Ubuntu 配置镜像源(ARM)

    [Ubuntu]Ubuntu 配置镜像源(ARM) 零.起因 最近在QEMU中安装了个ubuntu-24.04-live-server-arm64,默认是国外的软件源,很慢,故替换到国内. 壹.替换 ...

  5. langchain0.3教程:聊天机器人进阶之方法调用

    我们思考一个问题:大语言模型是否能帮我们做更多的事情,比如帮我们发送邮件.默认情况下让大模型帮我们发送邮件,大模型会这样回复我们: 可以看到,大模型无法发送邮件,它只会帮我们生成一个邮件模板,然后让我 ...

  6. 超实用!Prompt程序员使用指南,大模型各角色代码实战案例分享

    提示词(Prompt)是输入给大模型(LLM)的文本指令,用于明确地告诉大模型你想要解决的问题或完成的任务,也是大语言模型理解用户需求并生成准确答案的基础.因此 prompt 使用的好坏,直接决定了大 ...

  7. MySql字符集从utf8升级到utf8mb4说明和实现方式[详细]

    起源,项目中出现了异常,Message:Incorrect string value: '\xF0\x9F\x87\xB5\xF0\x9F...' for column 'signature' at ...

  8. pnpm create vite my-react-app --template react-ts

    npm install -D pnpm npm install -D vite pnpm create vite my-react-app --template react-ts npx vite - ...

  9. 面试官:如果某个业务量突然提升100倍QPS你会怎么做?

    "假设你负责的系统,某个业务线的QPS突然暴增100倍,你会怎么应对?" --这是上周朋友去面试,被问到一道题,他答了"加机器扩容",结果面试官眉头一皱:&qu ...

  10. 端口telnet不通排查过程

    现状 简单描述下最近在做啥,我手里维护的一些系统的线上服务器,还在使用centos7,7.3/7.6/7.9都有,运维侧选定的替换系统是openEuler20.03-LTS-SP1.按理说,运维直接在 ...