创建数据库事件触发器语法
1 CREATE [OR REPLACE] TRIGGER trigger_name
2 {BEFORE | AFTER} {database_event} ON {DATABASE | SCHEMA}
3 DECLARE
4 Variable declarations
5 BEGIN
6 ...some code...
7 END;
数据库事件触发器是发生在数据库范围的事件时触发的。有6个数据库事件触发器。
STARTUP
数据库打开时触发的。
没有before startup触发器。
Example:
CREATE OR REPLACE TRIGGER startup_pinner
AFTER STARTUP ON DATABASE
BEGIN
pin_plsql_packages;
pin_application_packages;
END;
SHUTDOWN
数据库正常关闭时触发的。
没有after shutdown 触发器。
Example:
CREATE OR REPLACE TRIGGER before_shutdown
BEFORE SHUTDOWN ON DATABASE
BEGIN
gather_system_stats;
END;
注意:只有在正常关闭情况下,shutdown nomal或者shutdown immediate时触发,非正常关闭shutdown abort不能触发。
SERVERERROR
当数据库发生错误时触发。
没有before servererror触发器。
Example:
DROP TRIGGER error_logger;
DROP TABLE error_log;
CREATE SEQUENCE error_seq;
CREATE TABLE error_log
(error_id NUMBER,
username VARCHAR2(30),
error_number NUMBER,
sequence NUMBER,
timestamp DATE);
CREATE OR REPLACE TRIGGER error_logger
AFTER SERVERERROR
ON SCHEMA
DECLARE
v_errnum NUMBER; -- the Oracle error #
v_now DATE := SYSDATE; -- current time
BEGIN
-- for every error in the error stack...
FOR e_counter IN 1..ORA_SERVER_ERROR_DEPTH LOOP
-- write the error out to the log table; no
-- commit is required because we are in an
-- autonomous transaction
INSERT INTO error_log(error_id,
username,
error_number,
sequence,
timestamp)
VALUES(error_seq.nextval,
USER,
ORA_SERVER_ERROR(e_counter),
e_counter,
v_now);
END LOOP; -- every error on the stack
END;
/
LOGON
当开始一个数据库会话时触发。
没有before logon触发器。
Example:
CREATE OR REPLACE TRIGGER after_logon
AFTER LOGON ON SCHEMA
DECLARE
v_sql VARCHAR2(100) := 'ALTER SESSION ENABLE RESUMABLE ' ||
'TIMEOUT 10 NAME ' || '''' ||
'OLAP Session' || '''';
BEGIN
EXECUTE IMMEDIATE v_sql;
DBMS_SESSION.SET_CONTEXT('OLAP Namespace',
'Customer ID',
load_user_customer_id);
END;
LOGOFF
当一个数据库会话正常终止时触发。
没有after logoff触发器。
Example:
CREATE OR REPLACE TRIGGER before_logoff
BEFORE LOGOFF ON DATABASE
BEGIN
gather_session_stats;
END;
DB_ROLE_CHANGE
当一个备用数据库切换成主数据库时或者反过来,触发。
多用于dataguard。
本文链接
昨天有个同事找我看了一段SQL,说是很慢,我首先看了看执行计划,发现COST很大,但是同时我也发现分区读取的有很大的问题。表示这样的:
(
day_id number
)
partition by range(day_id)
(
partition part_0 values less than(20130228),
partition part_1 values less than(20130301),
partition part_2 values less than(20130302),
partition part_3 values less than(20130303),
partition part_4 values less than(20130304),
partition part_5 values less than(20130305),
partition part_6 values less than(20130306)
)
表中的数据如下:
查询是这样子的:
执行计划是这样的:
可以看出来,一口气把所有的分区都读上了,但是按照我的想法,应该是只读取part_0和part_1这两个分区。后来我把这个SQL改成了这样:
这个时候的执行计划就是这样的:
这样就好了,只读取了需要的分区,这样子查询效率也有了很大的提高。生产系统中一天会有3GB的数据,所以如果按照第一个SQL写,那么就会读到这个表所有的分区,数据量就非常可观了,如果只读取自己需要的一个月的分区,就要小多了,COST也降低了很多。
我记得以前写过一个不能用到索引的情况:http://www.cnblogs.com/wingsless/archive/2011/11/19/2255647.html。昨天遇到这个情况以后发现分区也有这样那样的限制,还是原来写的那句话,一定要慎之又慎的写SQL。http://www.cnblogs.com/wingsless/archive/2013/03/09/2951618.html。
本文链接