被Oracle触发器给坑了

例行检查数据库AWR报告,有一条update语句执行多次,每次执行时间30多秒,这条SQL语句很简单,就是根据主键条件修改数据,主键个数是1到100之间。这个问题由来已久,只是偶尔出现。主键是varchar2,类似序列,由于之前有迁移过数据,特别在主键上为迁移的这部分数据加过标记,用肉眼看主键的分布是不均匀的。

第一次诊断:这个表有150万的数据,执行慢是因为update的时候没走到主键索引,于是去看了下直方图的分布,只有两个桶,于是重新收集了主键的直方图信息,有250个桶了。准备观察一天,第二天再看AWR,发现反而越来越慢了。

第二次诊断:听开发人员说此表上有触发器,测试发现果然是触发器的问题,触发器消耗的资源统统记在update语句上,让人感到莫名其妙。修改方法是将触发器的业务通过SQL实现,整个功能快了不少。下面对问题进行抽象、实验:

1.初始化数据及建立触发器

drop table test1 purge;

drop table test2 purge;

create table test1 as select * from dba_objects;

insert into test1 select  * from dba_objects;

commit;

create table test2 as select * from dba_objects;

create index ind_t1_object_id on test1(object_id) nologging;

create index ind_t2_object_id on test2(object_id) nologging;

exec dbms_stats.gather_table_stats(user,‘test1‘,cascade => true);

exec dbms_stats.gather_table_stats(user,‘test2‘,cascade => true);

CREATE OR REPLACE TRIGGER t_trigger

BEFORE update ON test1

FOR EACH ROW

BEGIN

update test2 t

set t.object_name = :old.object_name

where t.object_id = :old.object_id;

END;

SQL> set autotrace traceonly

SQL> set timing on

2.执行update语句会触发触发器

SQL> update test1 set object_name=‘‘||object_name;

已更新140300行。

已用时间:  00: 00: 15.21

执行计划

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

Plan hash value: 160929213

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

| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | UPDATE STATEMENT   |       |   140K|  4110K|   384   (1)| 00:00:06 |

|   1 |  UPDATE            | TEST1 |       |       |            |          |

|   2 |   TABLE ACCESS FULL| TEST1 |   140K|  4110K|   384   (1)| 00:00:06 |

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

统计信息

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

     140739  recursive calls

427013  db block gets

282079  consistent gets

0  physical reads

120365752  redo size

718  bytes sent via SQL*Net to client

498  bytes received via SQL*Net from client

4  SQL*Net roundtrips to/from client

3  sorts (memory)

0  sorts (disk)

140300  rows processed

SQL> commit;

提交完成。

3.disable触发器

SQL> alter trigger t_trigger disable;

4.执行update语句不会触发触发器

SQL> update test1 set object_name=‘‘||object_name;

已更新140300行。

已用时间:  00: 00: 01.67

执行计划

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

Plan hash value: 160929213

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

| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |

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

|   0 | UPDATE STATEMENT   |       |   140K|  3425K|   384   (1)| 00:00:06 |

|   1 |  UPDATE            | TEST1 |       |       |            |          |

|   2 |   TABLE ACCESS FULL| TEST1 |   140K|  3425K|   384   (1)| 00:00:06 |

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

统计信息

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

        389  recursive calls

144840  db block gets

2216  consistent gets

0  physical reads

50003740  redo size

721  bytes sent via SQL*Net to client

498  bytes received via SQL*Net from client

4  SQL*Net roundtrips to/from client

8  sorts (memory)

0  sorts (disk)

140300  rows processed

总结:通过两次实验可以看到资源消耗差别非常大,触发器消耗的资源都算在update上。触发器是每行触发,如果要高效,处理得有批量的思想。本次问题的解决,如果不是开发人员告诉我有触发器,这个问题真的很难找出来。

时间: 2024-10-09 22:26:08

被Oracle触发器给坑了的相关文章

oracle触发器、序列、任务计划练习一例

今天在闲暇时间练习了一下oracle任务计划,具体详情如下 1.创建表 TBL_TIME create table tbl_time( id number not null,    /*id号*/ vsecond varchar2(2),   /* 秒*/ vtime varchar2(10)    /*当前时间*/ ) 2.创建序列 seq_tbltime create sequence seq_tbltime start with 1 increment by 1 nomaxvalue no

oracle 触发器与事务

(1)如果外部事务撤销,触发器形成的变更是否会撤销?如果触发器操作失败,是否会导致外部SQL失败,从而导致事务撤销(2) 事务回滚时,触发器形成的变更是否会撤销:(3) 触发器失败时,外部SQL是否会返回错误:如果会,则研究如何不返回错,如果不会,则研究如何会返回错误:(4) 触发器失败时(插入两条记录,前者成功,后者失败),事务回滚时触发器形成的变更是否会撤销:(5) 触发器失败时(插入两条记录,前者成功,后者失败),事务提交时触发器形成的变更是否会撤销: 答 在oracle中,对触发器的限制

oracle 触发器 学习笔记

触发器 是特定事件出现的时候,自动执行的代码块.类似于存储过程,但是用户不能直接调用他们. 功能: 1. 允许/限制对表的修改 2. 自动生成派生列,比如自增字段 3. 强制数据一致性 4. 提供审计和日志记录 5. 防止无效的事务处理 6. 启用复杂的业务逻辑 开始 create trigger biufer_employees_department_id before insert or update of department_id on employees referencing old

Oracle触发器如何调用Java实现Openfire消息发送

写在前面,要想实现整个过程的成功执行请先准备以下文件: 1. 登陆Openfire服务端以及Spark客户端相关程序(openfire_4_0_1.exe.spark_2_7_6.exe) 2. 连接Openfire和Oracle相关的jar包(presence.jar.smack.jar.smackx-debug.jar.smackx.jar.ojdbc.jar)  Step1:安装Openfire服务端并配置数据库连接,配置参考<Openfire服务器安装与配置教程> Step2:在Ecl

oracle触发器使用总结

永不放弃,一切皆有可能!!! 只为成功找方法,不为失败找借口! oracle触发器使用总结 1.说明 1)触发器是一种特殊的存储过程,触发器一般由事件触发并且不能接受参数,存储器由语句块去调用 2)触发器分类: 1.DML触发器: 创建在表上,由DML事件引发 2.instead of触发器: 创建在视图上并且只能在行级上触发,用于替代insert,delete等操作(由于oracle中不能直接对有两个以上的表建立的视图进行DML操作,所以给出替代触发器,它是专门为进行视图操作的一种处理方法)

Oracle 触发器在日志管理开发中的应用

摘要: 本文讨论了利用数据库中的触发器对日志管理进行设计与实现的方法, 是对原来在客户端软件中编写日志管理方法的一种改进, 并给出了 Oracle9i 中的实例演示.关键词: Oracle; 触发器; 日志管理中图分类号: TP311文献标识码: A文章编号: 1009- 3044(2008)16- 21186- 02The Application of Oracle Trigger in the Developing of Log ManagementWU Heng- liang, ZHANG

【database】oracle触发器基础

一.oracle触发器基本语法 CREATE [OR REPLACE] TRIGGER trigger_name {BEFORE | AFTER } {INSERT | DELETE | UPDATE [OF column [, column -]]} [OR {INSERT | DELETE | UPDATE [OF column [, column -]]}...] ON [schema.]table_name | [schema.]view_name [REFERENCING {OLD [

Mybatis 插入操作时获取主键 (Oracle 触发器与SEQ)

1.通过Oracle序列 -- Create sequence create sequence SEQ_DW_EWSYSTEM minvalue 1 maxvalue 999999999999999999999999999 start with 1 increment by 1 cache 20; <insert id="insertEwsystem" parameterType="Ewsystem"> <selectKey keyProperty

(转)oracle触发器使用:after insert 与before insert的简单使用注意

本文转载自:http://blog.csdn.net/kuangfengbuyi/article/details/41446125 创建触发器时,触发器类型为after insert , 在begin中 Select fieldA into v_a from tableA; 执行到此句时,会出错: --弹出错误信息提示 --ORA-04091:表tr_table发生了变化触发器/函数不能读它 --ORA-06512: 在iu_table line 2 --ORA-04088: 触发器iu_tab