有關使用PL/SQL提高效能的學習:
最近遇到一些有關sql優化的問題,於是學習了有關使用PL/SQL提高效能的部分,以下摘錄的是以前沒有特別注意的部分,並且附有試驗的例子。
1、使用rowid進行跌代處理,通過rowid檢索資料是最快的方法,甚至比唯一參考索引還快。
如果在迴圈中需要根據cursor取到的條件進行進一步的操作,則在cursor中同時取出rowid,並且根據rowid定位記錄會是個高效率的方法,比取到主鍵或者唯一性索引的效率都好。
以下的例子是取表的10萬條記錄進行後續處理,id是該表的主鍵。優化後節省將近2秒鐘,效率提升16%。
優化前:
declare
cursor cur_test is
select id from user_tab
where rownum <= 100000;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in cur_test loop
update user_tab
set user_name = user_name
where id = n_row.id;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
20050420 10:40:14.791
20050420 10:40:26.509
PL/SQL procedure successfully completed.
優化後:
declare
cursor cur_test is
select rowid from user_tab
where rownum <= 100000;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in cur_test loop
update user_tab
set user_name = user_name
where rowid = n_row.rowid;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
20050420 10:40:38.112
20050420 10:40:48.051
PL/SQL procedure successfully completed.
2、確保比較運算中的資料型別相同。
要確保在where條件中的等號左右的資料型別是一致的,否則oracle雖然會進行自動的轉換,但是效率上會有所缺失。
3、根據條件出現的頻率來排序IF條件。
如果在塊兒中間有多個IF條件判斷,則應該考慮將命中率高的IF條件放在前面,這樣對效率的提升也是有好處的。
下面的例子迴圈1億次,判斷條件的次序調整,節省將近4秒鐘,效率提升23%。現在判斷條件後只是進行簡單的累加,如果是做更復雜的處理,效率的提升會更明顯。
優化前:
declare
ln_number number := 0;
ln_if number := 0;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..100000000 loop
if ln_if = 1 then
ln_number := ln_number + 1;
elsif ln_if = 0 then
ln_number := ln_number + 2;
end if;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 10:56:44.411
20050420 10:57:01.062
PL/SQL procedure successfully completed.
優化後:
declare
ln_number number := 0;
ln_if number := 0;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..100000000 loop
if ln_if = 0 then
ln_number := ln_number + 1;
elsif ln_if = 1 then
ln_number := ln_number + 2;
end if;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 10:57:01.498
20050420 10:57:14.385
PL/SQL procedure successfully completed.
4、使用PLS_INTEGER PL/SQL資料型別進行整數運算。
這種資料型別可以用於代替各種數值資料系列型別的宣告中,只要變數的值是一個整數,且在-2147483647到+2147483647。該資料型別可以使用更少的內部命令來處理,因此用這種資料型別可以提高效能。
這種資料型別可以替代整數的NUMBER型的變數定義,而實際的處理效率是比NUMBER型更快捷的。
以下的例子是個簡單的迭加,迴圈1億次,使用該資料型別節省大概0.5秒的時間,效率提升16%,不知道對於更復雜的資料處理,是不是效率上會有更大的提升。
優化前:
declare
ln_number number;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..100000000 loop
ln_number := ln_number + 1;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 10:47:17.676
20050420 10:47:21.301
PL/SQL procedure successfully completed.
優化後:
declare
ln_number pls_integer;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..100000000 loop
ln_number := ln_number + 1;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 10:47:21.989
20050420 10:47:25.149
PL/SQL procedure successfully completed.
5、減少對SYSDATE的呼叫
單獨取SYSDATE的時候不再需要從dual表中獲得,可以直接付給變數:
ld_date := sysdate;
但是應該減少呼叫SYSDATE的次數,如果可以,應該在塊兒的最開始付給某個變數,而不是需要的時候再取得,除非你需要精確的時間戳。
下面的例子迴圈10萬次,分別在迴圈中取得時間和迴圈外取得時間,節省時間0.152秒,效率提升99%。但是要注意這兩個不是等價的優化,如果你需要每次迴圈取得不同的時間戳,就應該將按照前面的指令碼編寫。
優化前:
declare
ld_date date;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..100000 loop
ld_date := sysdate;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:32:41.432
20050420 11:32:41.586
PL/SQL procedure successfully completed.
優化後:
declare
ld_date date;
ld_date1 date;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
ld_date1 := sysdate;
for n_row in 1..100000 loop
ld_date := ld_date;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:32:42.218
20050420 11:32:42.220
PL/SQL procedure successfully completed.
6、減少MOD函式的使用,可以用其他函式代替,但是效率不同。
不是所有的oracle函式的效率支出是等同的,MOD就是個消耗會比較多的函式,雖然他的功能是不錯的,但是如果可以用其他的函式取代,應減少該函式的使用次數。
下面的例子是進行了100萬次迴圈,分別使用mod作為判斷條件或者不使用,優化後節省0.7秒多,效率提升90%。
優化前:
declare
ln_number pls_integer := 0;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..1000000 loop
ln_number := ln_number + 1;
if mod(ln_number,1000) = 0 then
ln_number := ln_number + 2;
end if;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:20:34.435
20050420 11:20:35.225
PL/SQL procedure successfully completed.
優化後:
declare
ln_number pls_integer := 0;
ln_num1 pls_integer := 0;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..1000000 loop
ln_number := ln_number + 1;
ln_num1 := ln_num1 + 1;
if ln_num1 = 1000 then
ln_number := ln_number + 2;
ln_num1 := 0;
end if;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:20:35.461
20050420 11:20:35.542
PL/SQL procedure successfully completed.
7、將參考表載入到PL/SQL表中可以加快查詢速度。這是因為利用了PL/SQL中陣列索引的優勢。
下面這個例子是主表100萬條記錄,根據主鍵取參考表的對應欄位,參考表只有6條記錄。優化後的節省將近45秒,效率提升97%。
優化前:
declare
cursor cur_test is
select changecentsreason_id
from usercentsdetails_tab
where rownum <= 1000000;
ls_name changecentsreason_tab.changecentsreason%type;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in cur_test loop
select changecentsreason
into ls_name
from changecentsreason_tab
where id = n_row.changecentsreason_id;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
20050420 10:21:09.461
20050420 10:21:55.407
PL/SQL procedure successfully completed.
優化後:
declare
type ref_array is table of varchar2(20) index by binary_integer;
ref_tab ref_array;
cursor cur_test is
select changecentsreason_id
from usercentsdetails_tab
where rownum <= 1000000;
cursor cur_ref is
select id,changecentsreason
from changecentsreason_tab;
ls_name changecentsreason_tab.changecentsreason%type;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row1 in cur_ref loop
ref_tab(n_row1.id) := n_row1.changecentsreason;
end loop;
for n_row in cur_test loop
ls_name := ref_tab(n_row.changecentsreason_id);
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
20050420 10:19:20.333
20050420 10:19:21.604
PL/SQL procedure successfully completed.
8、時間範圍的取得
以前為了查詢一整天的記錄,我通常的寫法是:
between to_date(sysdate) - 1 and to_date(to_char(to_date(sysdate),'yyyymmdd')||' 23:59:59','yyyymmdd hh24:mi:ss') - 1
多次的格式轉換對效能也是有影響的,寫成:
between to_date(sysdate) - 1 and to_date(sysdate) - 0.000011574
0.000011574表示1秒。這樣的效率應該會有所提升。
下面的例子迴圈了100萬次,優化後節省36秒多,效率提升89%。不過這是比較特別的情況,因為其實不需要在迴圈中這樣做的,迴圈只是放大了效率提升的效果。
優化前:
declare
ld_date date ;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..1000000 loop
ld_date := to_date(to_char(to_date(sysdate),'yyyymmdd')||' 23:59:59','yyyymmdd hh24:mi:ss') - 1;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:24:19.530
20050420 11:24:50.525
PL/SQL procedure successfully completed.
優化後:
declare
ld_date date ;
begin
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
for n_row in 1..1000000 loop
ld_date := to_date(sysdate) - 0.000011574;
end loop;
dbms_output.put_line(to_char(SYSTIMESTAMP,'yyyymmdd hh24:mi:ss.ff3'));
end;
/
20050420 11:24:50.750
20050420 11:25:05.229
PL/SQL procedure successfully completed.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/51862/viewspace-180634/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PL/SQL 學習日記SQL
- [PL/SQL]10g PL/SQL學習筆記(一)SQL筆記
- [PL/SQL]10g PL/SQL學習筆記(二)SQL筆記
- [PL/SQL]10g PL/SQL學習筆記(三)SQL筆記
- 使用profiler測試Oracle PL/SQL效能OracleSQL
- 【PL/SQL 學習】隱式遊標學習SQL
- PL/SQL學習筆記-1SQL筆記
- PL/SQL學習筆記-2SQL筆記
- PL/SQL學習筆記-3SQL筆記
- PL/SQL學習筆記-4SQL筆記
- PL/SQL學習筆記-5SQL筆記
- PL/SQL學習筆記-6SQL筆記
- 提高SQL效能SQL
- 提高sql效能的方法SQL
- PL/SQL學習筆記-總結SQL筆記
- Oracle之PL/SQL基礎學習OracleSQL
- 使用DBMS_PROFILER進行PL/SQL效能分析SQL
- pl/sql練習SQL
- pl/sql 練習SQL
- pl/sql developer中關於TIMESTAMP顯示格式的疑問和學習SQLDeveloper
- oracle學習筆記(十五) PL/SQL語法結構以及使用Oracle筆記SQL
- 五種提高SQL效能的方法SQL
- 五種提高 SQL 效能的方法SQL
- 提高SQL查詢效能SQL
- PL/SQl Developer使用SQLDeveloper
- PL/SQL Developer 使用SQLDeveloper
- PL/Sql循序漸進全面學習教程--OracleSQLOracle
- 【PL/SQL 學習】PLS-00201SQL
- Oracle之PL/SQL基礎學習之二OracleSQL
- PL/SQL 批次Bind Forall 的效能表現SQL
- 使用DBMS_HPROF評測PL/SQL程式碼效能(上)SQL
- 使用PL/Scope分析PL/SQL程式碼SQL
- delete相關的pl/sql調優deleteSQL
- PL/SQL相關的資料字典SQL
- PL/SQL經典學習筆記(6-10)SQL筆記
- PL/SQL經典學習筆記(2-5)SQL筆記
- Oracle 的PL/SQL語言使用OracleSQL
- pl/sql for loop迴圈的使用SQLOOP