1. 程式人生 > >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 as old_value
     new as new_value
 for each row
 when (new_value.department_id<>80 )
begin
 :new_value.commission_pct :=0;
end;
/

觸發器的組成部分:
1、 觸發器名稱
2、 觸發語句
3、 觸發器限制
4、 觸發操作

1、 觸發器名稱
create trigger biufer_employees_department_id
命名習慣:
biufer(before insert update for each row)
employees 表名
department_id 列名

2、 觸發語句
比如:
表或檢視上的dml語句
ddl語句
資料庫關閉或啟動,startup shutdown 等等
before insert or update
  of department_id
  on employees
 referencing old as old_value
     new as new_value
 for each row

說明:
1、 無論是否規定了department_id ,對employees表進行insert的時候
2、 對employees表的department_id列進行update的時候

3、 觸發器限制
when (new_value.department_id<>80 )

限制不是必須的。此例表示如果列department_id不等於80的時候,觸發器就會執行。
其中的new_value是代表跟新之後的值。

4、 觸發操作
是觸發器的主體
begin
 :new_value.commission_pct :=0;
end;

主體很簡單,就是將更新後的commission_pct列置為0

觸發:
insert into employees(employee_id,
last_name,first_name,hire_date,job_id,email,department_id,salary,commission_pct )
values( 12345,’chen’,’donny’, sysdate, 12,

[email protected]’,60,10000,.25);

select commission_pct from employees where employee_id=12345;

觸發器不會通知使用者,便改變了使用者的輸入值。


觸發器型別:
1、 語句觸發器
2、 行觸發器
3、 instead of 觸發器
4、 系統條件觸發器
5、 使用者事件觸發器

1、 語句觸發器
是在表上或者某些情況下的檢視上執行的特定語句或者語句組上的觸發器。能夠與insert、update、delete或者組合上進行關聯。但是無論使用什麼樣的組合,各個語句觸發器都只會針對指定語句啟用一次。比如,無論update多少行,也只會呼叫一次update語句觸發器。

例子:
需要對在表上進行dml操作的使用者進行安全檢查,看是否具有合適的特權。
create table foo(a number);

create trigger biud_foo
 before insert or update or delete
  on foo
begin
 if user not in (‘donny’) then
  raise_application_error(-20001, ‘you don’t have access to modify this table.’);
 end if;
end;
/

即使sys,system使用者也不能修改foo表


對修改表的時間、人物進行日誌記錄。

1、 建立試驗表
create table employees_copy as select *from hr.employees

2、 建立日誌表
create table employees_log(
  who varchar2(30),
  when date);

3、 在employees_copy表上建立語句觸發器,在觸發器中填充employees_log 表。
create or replace trigger biud_employee_copy
  before insert or update or delete
   on employees_copy
 begin
  insert into employees_log(
   who,when)
  values( user, sysdate);
 
 end;
 /
4、 測試
update employees_copy set salary= salary*1.1;

select *from employess_log;

5、 確定是哪個語句起作用?
即是insert/update/delete中的哪一個觸發了觸發器?
可以在觸發器中使用inserting / updating / deleting 條件謂詞,作判斷:
begin
  if inserting then
   -----
  elsif updating then
   -----
  elsif deleting then
   ------
  end if;
end;

if updating(‘col1’) or updating(‘col2’) then
  ------
end if;


1、 修改日誌表
alter table employees_log
  add (action varchar2(20));

2、 修改觸發器,以便記錄語句型別。
create or replace trigger biud_employee_copy
  before insert or update or delete
   on employees_copy
 declare
  l_action employees_log.action%type;
 begin
  if inserting then
   l_action:=’insert’;
  elsif updating then
   l_action:=’update’;
  elsif deleting then
   l_action:=’delete’;
  else
   raise_application_error(-20001,’you should never ever get this error.’);

  insert into employees_log(
   who,action,when)
  values( user, l_action,sysdate);
 end;
 /

3、 測試
insert into employees_copy( employee_id, last_name, email, hire_date, job_id)
 values(12345,’chen’,’[email protected]’,sysdate,12);

select *from employees_log

update employees_copy set salary=50000 where employee_id = 12345;

2、 行觸發器
是指為受到影響的各個行啟用的觸發器,定義與語句觸發器類似,有以下兩個例外:
1、 定義語句中包含for each row子句
2、 在before……for each row觸發器中,使用者可以引用受到影響的行值。
比如:

定義:
create trigger biufer_employees_department_id
 before insert or update
  of department_id
  on employees_copy
 referencing old as old_value
     new as new_value
 for each row
 when (new_value.department_id<>80 )
begin
 :new_value.commission_pct :=0;
end;
/

referencing 子句:
執行dml語句之前的值的預設名稱是 :old ,之後的值是 :new
insert 操作只有:new
delete 操作只有 :old
update 操作兩者都有

referencing子句只是將new 和old重新命名為new_value和old_value,目的是避免混淆。比如操作一個名為new的表時。
作用不很大。

:為主健生成自增序列號

drop table foo;
create table foo(id number, data varchar2(20));
create sequence foo_seq;

create or replace trigger bifer_foo_id_pk
 before insert on foo
 for each row
begin
 select foo_seq.nextval into :new.id from dual;
end;
/

insert into foo(data) values(‘donny’);
insert into foo values(5,’chen’);
select * from foo;

3、 instead of 觸發器更新檢視

create or replace view company_phone_book as
 select first_name||’, ’||last_name name, email, phone_number,
employee_id emp_id
from hr.employees;

嘗試更新email和name
update hr.company_phone_book
 set name=’chen1, donny1’
where emp_id=100

create or replace trigger update_name_company_phone_book
instead of
update on hr.company_phone_book
begin
 update hr.employees
  set employee_id=:new.emp_id,
   first_name=substr(:new.name, instr(:new.name,’,’)+2),
   last_name= substr(:new.name,1,instr(:new.name,’,’)-1),
   phone_number=:new.phone_number,
   email=:new.email
 where employee_id=:old.emp_id;
end;

4、 系統事件觸發器
系統事件:資料庫啟動、關閉,伺服器錯誤

create trigger ad_startup
 after startup
  on database
begin
 -- do some stuff
end;
/


5、 使用者事件觸發器
使用者事件:使用者登陸、登出,create / alter / drop / analyze / audit / grant / revoke / rename / truncate / logoff

例子:記錄刪除物件

1. 日誌表
create table droped_objects(
 object_name varchar2(30),
 object_type varchar2(30),
 dropped_on date);

2.觸發器
create or replace trigger log_drop_trigger
 before drop on donny.schema
begin
 insert into droped_objects values(
  ora_dict_obj_name,  -- 與觸發器相關的函式
  ora_dict_obj_type,
  sysdate);
end;
/


3. 測試
create table drop_me(a number);
create view drop_me_view as select *from drop_me;
drop view drop_me_view;
drop table drop_me;

select *from droped_objects


禁用和啟用觸發器
alter trigger <trigger_name> disable;
alter trigger <trigger_name> enable;

事務處理:
在觸發器中,不能使用commit / rollback
因為ddl語句具有隱式的commit,所以也不允許使用

檢視:
dba_triggers

資料庫系統性能的提升不僅有賴於對資料庫本身效能的優化,還需要對應用程式的效能進行優化。本文分兩部分分別對這兩個方面進行介紹。

一個數據庫系統的生命週期可以分成設計、開發和成品三個階段。在設計階段進行資料庫效能優化的成本最低,收益最大。在成品階段進行資料庫效能優化的成本最高,收益最小。資料庫的優化可以通過對網路、硬體、作業系統、資料庫引數和應用程式的優化來進行。最常見的優化手段就是對硬體的升級。據統計,對網路、硬體、作業系統、資料庫引數進行優化所獲得的效能提升,全部加起來只佔資料庫系統性能提升的40%左右,其餘的60%系統性能提升來自對應用程式的優化。許多優化專家認為,對應用程式的優化可以得到80%的系統性能的提升。

資料庫效能的優化

資料庫設計是應用程式設計的基礎,其效能直接影響應用程式的效能。資料庫效能包括儲存空間需求量的大小和查詢響應時間的長短兩個方面。為了優化資料庫效能,需要對資料庫中的表進行規範化。規範化的正規化可分為第一正規化、第二正規化、第三正規化、bcnf正規化、第四正規化和第五正規化。一般來說,邏輯資料庫設計會滿足規範化的前3級標準,但由於滿足第三正規化的表結構容易維護且基本滿足實際應用的要求。因此,實際應用中一般都按照第三正規化的標準進行規範化。但是,規範化也有缺點:由於將一個表拆分成為多個表,在查詢時需要多表連線,降低了查詢速度。

由於規範化有可能導致查詢速度慢的缺點,考慮到一些應用需要較快的響應速度,在設計表時應同時考慮對某些表進行反規範化。反規範化可以採用以下幾種方法:

1. 分割表

分割表包括水平分割和垂直分割。

水平分割是按照行將一個表分割為多個表,這可以提高每個表的查詢速度,但查詢、更新時要選擇不同的表,統計時要彙總多個表,因此應用程式會更復雜。

垂直分割是對於一個列很多的表,若某些列的訪問頻率遠遠高於其它列,就可以將主鍵和這些列作為一個表,將主鍵和其它列作為另外一個表。通過減少列的寬度,增加了每個資料頁的行數,一次i/o就可以掃描更多的行,從而提高了訪問每一個表的速度。但是由於造成了多表連線,所以應該在同時查詢或更新不同分割表中的列的情況比較少的情況下使用。

2. 保留冗餘列

當兩個或多個表在查詢中經常需要連線時,可以在其中一個表上增加若干冗餘的列,以避免表之間的連線過於頻繁。由於對冗餘列的更新操作必須對多個表同步進行,所以一般在冗餘列的資料不經常變動的情況下使用。

3. 增加派生列

派生列是由表中的其它多個列計算所得,增加派生列可以減少統計運算,在資料彙總時可以大大縮短運算時間。

應用程式效能的優化

應用程式的優化通常可分為兩個方面:原始碼和sql語句。由於涉及到對程式邏輯的改變,原始碼的優化在時間成本和風險上代價很高,而對資料庫系統性能的提升收效有限,因此應用程式的優化應著重在sql語句的優化。對於海量資料,劣質sql語句和優質sql語句之間的速度差別可以達到上百倍,可見對於一個系統不是簡單地能實現其功能就行,而是要寫出高質量的sql語句,提高系統的可用性。

下面就某些sql語句的where子句編寫中需要注意的問題作詳細介紹。在這些where子句中,即使某些列存在索引,但是由於編寫了劣質的sql,系統在執行該sql語句時也不能使用該索引,而同樣使用全表掃描,這就造成了響應速度的極大降低。

1. is null 與 is not null

不能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列的情況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高效能。

任何在where子句中使用is null或is not null的語句優化器是不允許使用索引的。

2. 聯接列

對於有聯接的列,即使最後的聯接值為一個靜態值,優化器不會使用索引的。例如,假定有一個職工表(employee),對於一個職工的姓和名分成兩列存放(first_name和last_name),現在要查詢一個叫喬治·布什(george bush)的職工。 下面是一個採用聯接查詢的sql語句:

select * from employee where first_name||""||last_name ="george bush";

上面這條語句完全可以查詢出是否有george bush這個員工,但是這裡需要注意,系統優化器對基於last_name建立的索引沒有使用。

當採用下面這種sql語句的編寫,oracle系統就可以採用基於last_name建立的索引:

select * from employee where first_name ="george" and last_name ="bush";

遇到下面這種情況又如何處理呢?如果一個變數(name)中存放著george bush這個員工的姓名,對於這種情況我們又如何避免全程遍歷使用索引呢?可以使用一個函式,將變數name中的姓和名分開就可以了,但是有一點需要注意,這個函式是不能作用在索引列上。下面是sql查詢指令碼:

select * from employee where first_name = substr("&&name",1,instr("&&name"," ")-1) and last_name = substr("&&name",instr("&&name’," ")+1) ;

3. 帶萬用字元(%)的like語句

同樣以上面的例子來看這種情況。目前的需求是這樣的,要求在職工表中查詢名字中包含bush的人。可以採用如下的查詢sql語句:

select * from employee where last_name like "%bush%";

這裡由於萬用字元(%)在搜尋詞首出現,所以oracle系統不使用last_name的索引。在很多情況下可能無法避免這種情況,但是一定要心中有底,萬用字元如此使用會降低查詢速度。然而當萬用字元出現在字串其他位置時,優化器就能利用索引。例如,在下面的查詢中索引得到了使用:

select * from employee where last_name like "c%";

4. order by語句

order by語句決定了oracle如何將返回的查詢結果排序。order by語句對要排序的列沒有什麼特別的限制,也可以將函式加入列中(象聯接或者附加等)。任何在order by語句的非索引項或者有計算表示式都將降低查詢速度。

仔細檢查order by語句以找出非索引項或者表示式,它們會降低效能。解決這個問題的辦法就是重寫order by語句以使用索引,也可以為所使用的列建立另外一個索引,同時應絕對避免在order by子句中使用表示式。

5. not

我們在查詢時經常在where子句使用一些邏輯表示式,如大於、小於、等於以及不等於等等,也可以使用and(與)、or(或)以及not(非)。not可用來對任何邏輯運算子號取反。下面是一個not子句的例子:

... where not (status ="valid")

如果要使用not,則應在取反的短語前面加上括號,並在短語前面加上not運算子。not運算子包含在另外一個邏輯運算子中,這就是不等於(<>)運算子。換句話說,即使不在查詢where子句中顯式地加入not詞,not仍在運算子中,見下例:

... where status <>"invalid";

再看下面這個例子:

select * from employee where salary<>3000;

對這個查詢,可以改寫為不使用not的語句:

select * from employee where salary<3000 or salary>3000;

雖然這兩種查詢的結果一樣,但是第二種查詢方案會比第一種查詢方案更快些。第二種查詢允許oracle對salary列使用索引,而第一種查詢則不能使用索引。

6. in和exists

有時候會將一列和一系列值相比較。最簡單的辦法就是在where子句中使用子查詢。在where子句中可以使用兩種格式的子查詢。

第一種格式是使用in操作符:

... where column in(select * from ... where ...);

第二種格式是使用exist操作符:

... where exists (select "x" from ...where ...);

絕大多數人會使用第一種格式,因為它比較容易編寫,而實際上第二種格式要遠比第一種格式的效率高。在oracle中可以將幾乎所有的in操作符子查詢改寫為使用exists的子查詢。

第二種格式中,子查詢以‘select "x"’開始。運用exists子句不管子查詢從表中抽取什麼資料它只檢視where子句。這樣優化器就不必遍歷整個表而僅根據索引就可完成工作(這裡假定在where語句中使用的列存在索引)。相對於in子句來說,exists使用相連子查詢,構造起來要比in子查詢困難一些。

通過使用exists,oracle系統會首先檢查主查詢,然後執行子查詢直到找到第一個匹配項,這就節省了時間。oracle系統在執行in子查詢時,首先執行子查詢,並將獲得的結果列表存放在一個加了索引的臨時表中。在執行子查詢之前,系統先將主查詢掛起,待子查詢執行完畢,存放在臨時表中以後再執行主查詢。這也就是使用exists比使用in通常查詢速度快的原因。

同時應儘可能使用not exists來代替not in,儘管二者都使用了not(不能使用索引而降低速度),但not exists要比not in查詢效率更高。
 

相關推薦

Oracle觸發器應用

觸發器 是特定事件出現的時候,自動執行的程式碼塊。類似於儲存過程,但是使用者不能直接呼叫他們。 功能:1、 允許/限制對錶的修改2、 自動生成派生列,比如自增欄位3、 強制資料一致性4、 提供審計和日誌記錄5、 防止無效的事務處理6、 啟用複雜的業務邏輯 開始create t

Oracle觸發器

prim let values err rac null insert tput dbms -----------------------------觸發器----------------------- --定義方式: create or replace trigger

ORACLE觸發器詳解

etc 遊標 target with get ger 獨立 erer mon 作者:indexman 觸發器是許多關系數據庫系統都提供的一項技術。在oracle系統裏,觸發器類似過程和函數,都有聲明,執行和異常處理過程的PL/SQL塊。 8.1 觸發器類型 觸

觸發器應用

values arc 分析 repl pla pri mysql ext 數據 3.觸發器實際應用 需求:使用序列,觸發器來模擬mysql中自增效果 案例中的效果是通過序列和觸發器來實現對user表中的id自增的效果 每次進行添加的時候,觸發器都會從序列中取出一個序列i

Oracle 12c應用連接VIP輪訓負載均衡?

vip 應用連接 目前很多生產數據庫都是兩節點RAC,應用連接的數據庫通常會連接SCAN IP或者VIP,這裏做一個小實驗,如果我們使用VIP連接,應該怎樣配置我們的客戶端,負載均衡是否是嚴格意義上的輪訓機制,只有通過自己的測試才能得到準備的答案。tnsnames.ora配置<rac01:orc

oracle觸發器 調用 web接口

錯誤信息 agen call lan gpo 測試 replace static throws 最近要求開發當數據表發生變化的時候調用web接口的需求,上網找了好幾篇文章看著都覺得不是很好,也根據別人的思路去實現了下,感覺都不太理想,最後使用URLConnection實現了

Oracle觸發器-變異表觸發器不能訪問本表

col 讀取 key commit 觸發器 圖片 gre mar nbsp 1 CREATE OR REPLACE TRIGGER trgregisterpregroup 2 AFTER UPDATE 3 ON tblregisterusers 4 FOR E

oracle--觸發器+序列實現自增

tid 表名 dual 方式 spa tar num declare end 1 create table test_table( 2 ID NUMBER PRIMARY KEY, 3 NAME VARCHAR2(10), 4

Oracle觸發器實例

before for trigger seq drop each ins gin new # 觸發器 create or replace trigger tr_tmp before insert on emp for each row begin select e

Oracle 10g 應用補丁PSU 10.2.0.5.180717

  最近測試了一下在Oracle 10g下面(單例項下面)升級、應用補丁PSU 10.2.0.5.180717,打這個補丁的主要原因是 Oracle 將於 2019年6月啟用新的SCN相容性,並且由於BigSCN的作用,96K每秒的SCN增速,都可能會使得通過DB Link的訪問產生SCN過度拉昇

oracle 觸發器 序列

使用序列生成ID create sequence SEQ_SPBBL(序列名稱) minvalue 1 maxvalue 9999999999999999999999999999 start with 1 increment by 1 cache 10; create or replace trigg

Oracle觸發器和事務

  oracle觸發器和事務 2015年11月24日 14:16:43 it_taojingzhan 閱讀數:320 編寫觸發器時,需要注意以下幾點: l        觸發

oracle:觸發器的使用

oracle:觸發器的使用 觸發器是許多關係資料庫系統都提供的一項技術。在oracle系統裡,觸發器類似過程和函式,都有宣告,執行和異常處理過程的PL/SQL塊。 1.1 觸發器型別 觸發器在資料庫裡以獨立的物件儲存,它與儲存過程和函式不同的是,儲存過程與函式需要使用者顯示呼叫才執行,而觸發器

oracle觸發器 invalid number 問題(寫好觸發器之後 測試的時候遇到的問題)

--之前程式碼寫完之後,觸發器建立成功了,但是沒測試 。。然後測試的時候出問題了 -- 執行update和delete操作的時候,報錯invalid number -- 後來發現時因為本地id型別是number,遠端是varchar2,而且遠端表裡邊有varchar2型別的id資料 -- 所以wh

oracle觸發器使用總結

  部落格園 首頁 新隨筆 聯絡 管理 訂閱 隨筆- 94  文章- 1  評論- 71  oracle觸發器使用總結 1.說明 1)觸發器是一種特殊的儲存過程,觸發器一般由事件觸發並且不能接受引數,

Oracle觸發器例項

# 觸發器 create or replace trigger tr_tmp before insert on emp for each row begin select empno_seq.nextval   into :new.empno from dual; end insert into

Oracle--觸發器

什麼是觸發器 觸發求器是一組完成特定功能的動作。這些動作由資料庫自動呼叫和執行。觸發器所執行的動作一般是一組DML操作。, 語句觸發器 語句觸發器的左右物件一般是資料表。其觸發動作是針對作用物件的Dml操作 建立語句觸發器 create trigger 觸發器

Oracle觸發器條件更改新插入記錄的欄位值

最近,有個專案功能需要在Oracle資料庫中對錶的記錄做動態更新,實現一插入指定條件的記錄,就修改相關欄位值。嘗試了下,最終做到每當插入時就能夠更新記錄某欄位值。 這裡用PL/SQL做了相關實現。 相關表名稱為Person ,其屬性欄位如下: 具體需求為:當插入記錄年齡(欄位A

oracle 觸發器實現級聯更新

create or replace TRIGGER 觸發器名字 AFTER UPDATE OF 更新表的更新列列名a1 ON 更新表表名a FOR EACH ROW BEGIN IF :OLD.更新表的更新列列名a1<>:NEW.更新表的更新列列名a1 THE

Oracle 觸發器的編寫-----》假設需求要在插入資料時,觸發觸發器生成附件ID (假如Excel動態匯入資料,列表欄再上傳附件,因此要插入資料時生成附件ID)

  /********************************************************************   功能名稱:  GET_BAIHOO_ID_BY_NAME   功能描述:  觸發觸發器生成附件ID &