『壹』 oracle存儲過程執行速度很慢是什麼原因
解決辦法:
你需要對你的表根據查詢條件設計相應的索引,有時候根據需要可能一個表你需要建立好幾個索引都是有可能的。然後再執行,你會發現原來要30幾秒的現在零點幾秒就可以搞定了,這跟使用游標沒什麼關系。游標的使用完全由你的應用需要決定,我相信能不用的你肯定不會選擇使用游標處理,一般是實在沒辦法的情況下才選擇游標去做。
你查詢慢的原因是你在存儲過程中執行的話,沒有索引時,他會一條一條查知道把80幾萬條數據全部掃描一遍直到查完了你才看到一個結果,但是你在外面單獨執行很快的原因是plsql他會首先去查查到幾條數據就先給你返回來,所以你馬上就看到結果了,但實際上查詢也並沒有結束,你要是數據很多的情況下你往下拉,你會發信很慢,其實查詢過程根本就還沒有結束。
總之寫存儲過程第一步是會寫,第二步是要做好優化,否則當你的數據量很大的時候你的過程寫的不好的話問題會馬上暴露出來。
『貳』 oracle 存儲過程
1.基本結構
CREATE OR REPLACE PROCEDURE 存儲過程名字
(
參數1 IN NUMBER,
參數2 IN NUMBER
) IS
變數1 INTEGER :=0;
變數2 DATE;
BEGIN
END 存儲過程名字
你那個 END P_UPDATELOCKCMPINFO; 沒看懂是啥意思
2.SELECT INTO STATEMENT
將select查詢的結果存入到變數中,可以同時將多個列存儲多個變數中,必須有一條
記錄,否則拋出異常(如果沒有記錄拋出NO_DATA_FOUND)
例子:
BEGIN
SELECT col1,col2 into 變數1,變數2 FROM typestruct where xxx;
EXCEPTION
WHEN NO_DATA_FOUND THEN
xxxx;
END;
...
3.IF 判斷
IF V_TEST=1 THEN
BEGIN
do something
END;
END IF;
4.while 循環
WHILE V_TEST=1 LOOP
BEGIN
XXXX
END;
END LOOP;
5.變數賦值
V_TEST := 123;
6.用for in 使用cursor
...
IS
CURSOR cur IS SELECT * FROM xxx;
BEGIN
FOR cur_result in cur LOOP
BEGIN
V_SUM :=cur_result.列名1+cur_result.列名2
END;
END LOOP;
END;
7.帶參數的cursor
CURSOR C_USER(C_ID NUMBER) IS SELECT NAME FROM USER WHERE TYPEID=C_ID;
OPEN C_USER(變數值);
LOOP
FETCH C_USER INTO V_NAME;
EXIT FETCH C_USER%NOTFOUND;
do something
END LOOP;
CLOSE C_USER;
8.用pl/sql developer debug
連接資料庫後建立一個Test WINDOW
在窗口輸入調用SP的代碼,F9開始debug,CTRL+N單步調試
簡單實例,通過DBMS_OUTPUT來看結果
CREATE OR REPLACE PROCEDURE bb (lic_para IN VARCHAR2,out_para OUT VARCHAR2)
AS
temp VARCHAR2 (100);
BEGIN
SELECT lic_no
INTO temp
FROM t_vehicle_info
WHERE lic_no = lic_para;
out_para:=temp;
DBMS_OUTPUT.put_line (out_para);
END bb;
下面是調用:
begin
-- Call the procere
bb(lic_para => :lic_para,
out_para => :out_para);
end;
可以在命令行里敲sqlplus 「yonghuming/mima@dbname」接著調試存儲過程。但是最好用的是在pl/sql Developer工具裡面用點存儲過程里的TEST來調用,它能自動生成調用的語句並有欄目讓你輸入參數值,包括輸入參數和輸出參數,並把結果返回到輸出參數裡面,在結果欄可見,這點pl/sql Developer比TOAD要強,TOAD在存儲過程上右鍵後點擊EXECUTE Procere也可以執行,只是結果在那看我不曉得,而在pl/sql Developer按F9可以調試,ctrl+N可以單步跟蹤,的確爽
『叄』 oracle存儲過程問題(急)
DBMS_Job包的用法
包含以下子過程:
Broken()過程。
change()過程。
Interval()過程。
Isubmit()過程。
Next_Date()過程。
Remove()過程。
Run()過程。
Submit()過程。
User_Export()過程。
What()過程。
1、
Broken()過程更新一個已提交的工作的狀態,典型地是用來把一個已破工作標記為未破工作。
這個過程有三個參數:job 、broken與next_date。
PROCEDURE Broken (job IN binary_integer,
Broken IN boolean,
next_date IN date :=SYSDATE)
job參數是工作號,它在問題中唯一標識工作。
broken參數指示此工作是否將標記為破——TRUE說明此工作將標記為破,而FLASE說明此工作將標記為未破。
next_date參數指示在什麼時候此工作將再次運行。此參數預設值為當前日期和時間。
2、
Change()過程用來改變指定工作的設置。
這個過程有四個參數:job、what 、next_date與interval。
PROCEDURE Change (job IN binary_integer,
What IN varchar2,
next_date IN date,
interval IN varchar2)
此job參數是一個整數值,它唯一標識此工作。
What參數是由此工作運行的一塊PL/SQL代碼塊。
next_date參數指示何時此工作將被執行。
interval參數指示一個工作重執行的頻度。
3、
Interval()過程用來顯式地設置重執行一個工作之間的時間間隔數。
這個過程有兩個參數:job與interval。
PROCEDURE Interval (job IN binary_integer,
Interval IN varchar2)
job參數標識一個特定的工作。interval參數指示一個工作重執行的頻度。
4、
ISubmit()過程用來用特定的工作號提交一個工作。
這個過程有五個參數:job、what、next_date、interval與no_parse。
PROCEDURE ISubmit (job IN binary_ineger,
What IN varchar2,
next_date IN date,
interval IN varchar2,
no_parse IN booean:=FALSE)
這個過程與Submit()過程的唯一區別在於此job參數作為IN型參數傳遞且包括一個
由開發者提供的工作號。如果提供的工作號已被使用,將產生一個錯誤。
5、
Next_Date()過程用來顯式地設定一個工作的執行時間。這個過程接收兩個參數:job與next_date。
PROCEDURE Next_Date(job IN binary_ineger,
next_date IN date)
job標識一個已存在的工作。next_date參數指示了此工作應被執行的日期與時間。
6、
Remove()過程來刪除一個已計劃運行的工作。這個過程接收一個參數:
PROCEDURE Remove(job IN binary_ineger);
job參數唯一地標識一個工作。這個參數的值是由為此工作調用Submit()過程返回的job參數的值。
已正在運行的工作不能由調用過程序刪除。
7、
Run()過程用來立即執行一個指定的工作。這個過程只接收一個參數:
PROCEDURE Run(job IN binary_ineger)
job參數標識將被立即執行的工作。
8、
使用Submit()過程,工作被正常地計劃好。
這個過程有五個參數:job、what、next_date、interval與no_parse。
PROCEDURE Submit ( job OUT binary_ineger,
What IN varchar2,
next_date IN date,
interval IN varchar2,
no_parse IN booean:=FALSE)
job參數是由Submit()過程返回的binary_ineger。這個值用來唯一標識一個工作。
what參數是將被執行的PL/SQL代碼塊。
next_date參數指識何時將運行這個工作。
interval參數何時這個工作將被重執行。
no_parse參數指示此工作在提交時或執行時是否應進行語法分析——TRUE
指示此PL/SQL代碼在它第一次執行時應進行語法分析,
而FALSE指示本PL/SQL代碼應立即進行語法分析。
9、
User_Export()過程返回一個命令,此命令用來安排一個存在的工作以便此工作能重新提交。
此程序有兩個參數:job與my_call。
PROCEDURE User_Export(job IN binary_ineger,
my_call IN OUT varchar2)
job參數標識一個安排了的工作。my_call參數包含在它的當前狀態重新提交此工作所需要
的正文。
10、
What()過程應許在工作執行時重新設置此正在運行的命令。這個過程接收兩個參數:job與what。
PROCEDURE What (job IN binary_ineger,
What IN OUT varchar2)
job參數標識一個存在的工作。what參數指示將被執行的新的PL/SQL代碼。
一個簡單例子:
創建測試表
SQL> create table a(a date);
表已創建。
創建一個自定義過程
SQL> create or replace procere test as
2 begin
3 insert into a values(sysdate);
4 end;
5 /
過程已創建。
創建JOB
SQL> variable job1 number;
SQL>
SQL> begin
2 dbms_job.submit(:job1,'test;',sysdate,'sysdate+1/1440'); --每天1440分鍾,即一分鍾運行test過程一次
3 end;
4 /
PL/SQL 過程已成功完成。
運行JOB
SQL> begin
2 dbms_job.run(:job1);
3 end;
4 /
PL/SQL 過程已成功完成。
SQL> select to_char(a,'yyyy/mm/dd hh24:mi:ss') 時間 from a;
時間
-------------------
2001/01/07 23:51:21
2001/01/07 23:52:22
2001/01/07 23:53:24
刪除JOB
SQL> begin
2 dbms_job.remove(:job1);
3 end;
4 /
PL/SQL 過程已成功完成。
delete from BDZHB where SBH like '%X%' 這個sql就是查詢帶有X的全部記錄
『肆』 oracle存儲過程
create table dept
(deptno number,
dname varchar2(20),
loc varchar2(20)
)
1.如果你是取出單個的,你可以定義一個或者多個變數,將取出的值賦給變數
例如:
create or replace procere dept_procere(a in varchar2)
is
v_no number;
v_a varchar2(20);
begin
select a.deptno,a.loc into v_no,v_a
from dept a
where a.dname=a;
dbms_output.put_line('學號為:'||v_no||);
end;
2.如果你取出的是一個結果集,你可以用游標(一個簡單的例子)
create or replace procere dept_procere(a in varchar2,v_a out dept%rowtype)
is
--聲明游標
cursor c_de(a in varchar2)
is select * from dept where dname=a;
begin
--打開游標,對其中找到的記錄進行遍歷
open c_de(a);
loop
fetch c_de into v_a;
exit when c_de%notfound;
end loop;
close c_de;
dbms_output.put_line('deptno:'||v_a.deptno);
dbms_output.put_line('dname:'||v_a.dname);
dbms_output.put_line('loc:'||v_a.loc);
end;
3.可注意:在創建存儲過程的時候加上or replace,如果遇到重名的存儲過程將替換掉!
4.定義變數後面記得加上分號
5.oracle中可以對它直接賦值,可不用set, v_a:='a';
(6.給變數賦值的時候注意它的數據類型 a要單引號)
7.如果你這存儲過程是將參數賦值給一個你定義的變數的話,那這樣你不覺得是多此一舉么?一般將參數賦值給你定義的變數的話,可以進行數據類型轉換!可在此存儲過程中,沒發現它的用處
8.你取出來的數據,要放在變數或是游標中,顯示出來,不然你寫出來的存儲過程有什麼用呢?所以 select ...into ...
9.我也是剛學oracle的,希望可以互相學習一下,呵呵!上面的如有錯誤希望可以告訴我一下啊
『伍』 Oracle資料庫存儲過程中要寫一個睡眠時間,怎麼實現
DBMS_LOCK.sleep (5);
沒有用過,你自己試
『陸』 oracle中怎麼實現進程的睡眠和喚醒
1 Linux進程的睡眠和喚醒
在Linux中,僅等待CPU時間的進程稱為就緒進程,它們被放置在一個運行隊列中,一個就緒進程的狀 態標志位為TASK_RUNNING。一旦一個運行中的進程時間片用完, Linux 內核的調度器會剝奪這個進程對CPU的控制權,並且從運行隊列中選擇一個合適的進程投入運行。
當然,一個進程也可以主動釋放CPU的控制權。函數 schele()是一個調度函數,它可以被一個進程主動調用,從而調度其它進程佔用CPU。一旦這個主動放棄CPU的進程被重新調度佔用 CPU,那麼它將從上次停止執行的位置開始執行,也就是說它將從調用schele()的下一行代碼處開始執行。
有時候,進程需要等待直到某個特定的事件發生,例如設備初始化完成、I/O 操作完成或定時器到時等。在這種情況下,進程則必須從運行隊列移出,加入到一個等待隊列中,這個時候進程就進入了睡眠狀態。
Linux 中的進程睡眠狀態有兩種:一種是可中斷的睡眠狀態,其狀態標志位TASK_INTERRUPTIBLE;
另一種是不可中斷 的睡眠狀態,其狀態標志位為TASK_UNINTERRUPTIBLE。可中斷的睡眠狀態的進程會睡眠直到某個條件變為真,比如說產生一個硬體中斷、釋放 進程正在等待的系統資源或是傳遞一個信號都可以是喚醒進程的條件。不可中斷睡眠狀態與可中斷睡眠狀態類似,但是它有一個例外,那就是把信號傳遞到這種睡眠 狀態的進程不能改變它的狀態,也就是說它不響應信號的喚醒。不可中斷睡眠狀態一般較少用到,但在一些特定情況下這種狀態還是很有用的,比如說:進程必須等 待,不能被中斷,直到某個特定的事件發生。
在現代的Linux操作系統中,進程一般都是用調用schele()的方法進入睡眠狀態的,下面的代碼演
示了如何讓正在運行的進程進入睡眠狀態。
sleeping_task = current;
set_current_state(TASK_INTERRUPTIBLE);
schele();
func1();
/* Rest of the code ... */
在第一個語句中,程序存儲了一份進程結構指針sleeping_task,current 是一個宏,它指向正在執行
的進程結構。set_current_state()將該進程的狀態從執行狀態TASK_RUNNING 變成睡眠狀態
TASK_INTERRUPTIBLE。 如果schele()是被一個狀態為TASK_RUNNING 的進程調度,那麼schele()將調度另外一個進程佔用CPU;如果schele()是被一個狀態為TASK_INTERRUPTIBLE 或TASK_UNINTERRUPTIBLE 的進程調度,那麼還有一個附加的步驟將被執行:當前執行的進程在另外一個進程被調度之前會被從運行隊列中移出,這將導致正在運行的那個進程進入睡眠,因為 它已經不在運行隊列中了。
我們可以使用下面的這個函數將剛才那個進入睡眠的進程喚醒。
wake_up_process(sleeping_task);
在調用了wake_up_process()以後,這個睡眠進程的狀態會被設置為TASK_RUNNING,而且調度器
會把它加入到運行隊列中去。當然,這個進程只有在下次被調度器調度到的時候才能真正地投入運行。
2 無效喚醒
幾乎在所有的情況下,進程都會在檢查了某些條件之後,發現條件不滿足才進入睡眠。可是有的時候
進程卻會在 判定條件為真後開始睡眠,如果這樣的話進程就會無限期地休眠下去,這就是所謂的無效喚醒問題。在操作系統中,當多個進程都企圖對共享數據進行某種處理,而 最後的結果又取決於進程運行的順序時,就會發生競爭條件,這是操作系統中一個典型的問題,無效喚醒恰恰就是由於競爭條件導致的。
設想有兩個進程A 和B,A 進程正在處理一個鏈表,它需要檢查這個鏈表是否為空,如果不空就對鏈
表裡面的數據進行一些操作,同時B進程也在往這個鏈表添加節點。當這個鏈表是空的時候,由於無數據可操作,這時A進程就進入睡眠,當B進程向鏈表裡面添加了節點之後它就喚醒A 進程,其代碼如下:
A進程:
1 spin_lock(&list_lock);
2 if(list_empty(&list_head)) {
3 spin_unlock(&list_lock);
4 set_current_state(TASK_INTERRUPTIBLE);
5 schele();
6 spin_lock(&list_lock);
7 }
8
9 /* Rest of the code ... */
10 spin_unlock(&list_lock);
B進程:
100 spin_lock(&list_lock);
101 list_add_tail(&list_head, new_node);
102 spin_unlock(&list_lock);
103 wake_up_process(processa_task);
這里會出現一個問題,假如當A進程執行到第3行後第4行前的時候,B進程被另外一個處理器調度
投 入運行。在這個時間片內,B進程執行完了它所有的指令,因此它試圖喚醒A進程,而此時的A進程還沒有進入睡眠,所以喚醒操作無效。在這之後,A 進程繼續執行,它會錯誤地認為這個時候鏈表仍然是空的,於是將自己的狀態設置為TASK_INTERRUPTIBLE然後調用schele()進入睡 眠。由於錯過了B進程喚醒,它將會無限期的睡眠下去,這就是無效喚醒問題,因為即使鏈表中有數據需要處理,A 進程也還是睡眠了。
3 避免無效喚醒
如何避免無效喚醒問題呢?我們發現無效喚醒主要發生在檢查條件之後和進程狀態被設置為睡眠狀
態之前, 本來B進程的wake_up_process()提供了一次將A進程狀態置為TASK_RUNNING 的機會,可惜這個時候A進程的狀態仍然是TASK_RUNNING,所以wake_up_process()將A進程狀態從睡眠狀態轉變為運行狀態的努力 沒有起到預期的作用。要解決這個問題,必須使用一種保障機制使得判斷鏈表為空和設置進程狀態為睡眠狀態成為一個不可分割的步驟才行,也就是必須消除競爭條 件產生的根源,這樣在這之後出現的wake_up_process ()就可以起到喚醒狀態是睡眠狀態的進程的作用了。
找到了原因後,重新設計一下A進程的代碼結構,就可以避免上面例子中的無效喚醒問題了。
A進程:
1 set_current_state(TASK_INTERRUPTIBLE);
2 spin_lock(&list_lock);
3 if(list_empty(&list_head)) {
4 spin_unlock(&list_lock);
5 schele();
6 spin_lock(&list_lock);
7 }
8 set_current_state(TASK_RUNNING);
9
10 /* Rest of the code ... */
11 spin_unlock(&list_lock);
可以看到,這段代碼在測試條件之前就將當前執行進程狀態轉設置成TASK_INTERRUPTIBLE了,並且在鏈表不為空的情況下又將自己置為TASK_RUNNING狀態。這樣一來如果B進程在A進程進程檢查
了鏈表為空以後調用wake_up_process(),那麼A進程的狀態就會自動由原來TASK_INTERRUPTIBLE
變成TASK_RUNNING,此後即使進程又調用了schele(),由於它現在的狀態是TASK_RUNNING,所以仍然不會被從運行隊列中移出,因而不會錯誤的進入睡眠,當然也就避免了無效喚醒問題。
4 Linux內核的例子
在Linux操作系統中,內核的穩定性至關重要,為了避免在Linux操作系統內核中出現無效喚醒問題,
Linux內核在需要進程睡眠的時候應該使用類似如下的操作:
/* 『q』是我們希望睡眠的等待隊列 */
DECLARE_WAITQUEUE(wait,current);
add_wait_queue(q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
/* 或TASK_INTERRUPTIBLE */
while(!condition) /* 『condition』 是等待的條件*/
schele();
set_current_state(TASK_RUNNING);
remove_wait_queue(q, &wait);
上面的操作,使得進程通過下面的一系列步驟安全地將自己加入到一個等待隊列中進行睡眠:首先調
用DECLARE_WAITQUEUE ()創建一個等待隊列的項,然後調用add_wait_queue()把自己加入到等待隊列中,並且將進程的狀態設置為 TASK_INTERRUPTIBLE 或者TASK_INTERRUPTIBLE。然後循環檢查條件是否為真:如果是的話就沒有必要睡眠,如果條件不為真,就調用schele()。當進程 檢查的條件滿足後,進程又將自己設置為TASK_RUNNING 並調用remove_wait_queue()將自己移出等待隊列。
從上面可以看到,Linux的內核代碼維護者也是在進程檢查條件之前就設置進程的狀態為睡眠狀態,
然後才循環檢查條件。如果在進程開始睡眠之前條件就已經達成了,那麼循環會退出並用set_current_state()將自己的狀態設置為就緒,這樣同樣保證了進程不會存在錯誤的進入睡眠的傾向,當然也就不會導致出現無效喚醒問題。
下面讓我們用linux 內核中的實例來看看Linux 內核是如何避免無效睡眠的,這段代碼出自Linux2.6的內核(linux-2.6.11/kernel/sched.c: 4254):
4253 /* Wait for kthread_stop */
4254 set_current_state(TASK_INTERRUPTIBLE);
4255 while (!kthread_should_stop()) {
4256 schele();
4257 set_current_state(TASK_INTERRUPTIBLE);
4258 }
4259 __set_current_state(TASK_RUNNING);
4260 return 0;
上面的這些代碼屬於遷移服務線程migration_thread,這個線程不斷地檢查kthread_should_stop(),
直 到kthread_should_stop()返回1它才可以退出循環,也就是說只要kthread_should_stop()返回0該進程就會一直睡 眠。從代碼中我們可以看出,檢查kthread_should_stop()確實是在進程的狀態被置為TASK_INTERRUPTIBLE後才開始執行 的。因此,如果在條件檢查之後但是在schele()之前有其他進程試圖喚醒它,那麼該進程的喚醒操作不會失效。
小結
通過上面的討論,可以發現在Linux 中避免進程的無效喚醒的關鍵是在進程檢查條件之前就將進程的
狀態置為TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE,並且如果檢查的條件滿足的話就應該
將其狀態重新設置為TASK_RUNNING。這樣無論進程等待的條件是否滿足, 進程都不會因為被移出就緒隊列而錯誤地進入睡眠狀態,從而避免了無效喚醒問題。
『柒』 oracle的存儲過程
1.存儲過程可以使得程序執行效率更高、安全性更好,因為過程建立之後 已經編譯並且儲存到資料庫,直接寫sql就需要先分析再執行因此過程效率更高,直接寫sql語句會帶來安全性問題,如:sql注入
2.建立過程不會很耗系統資源,因為過程只是在調用才執行。
3.存儲過程可以用於降低網路流量,存儲過程代碼直接存儲於資料庫中,所以不會產生大量T-sql語句的代碼流量。
4.使用存儲過程使您能夠增強對執行計劃的重復使用,由此可以通過使用遠程過程調用 (RPC) 處理伺服器上的存儲過程而提高性能。RPC 封裝參數和調用伺服器端過程的方式使引擎能夠輕松地找到匹配的執行計劃,並只需插入更新的參數值。
5.可維護性高,更新存儲過程通常比更改、測試以及重新部署程序集需要較少的時間和精力。
6.代碼精簡一致,一個存儲過程可以用於應用程序代碼的不同位置。
7.增強安全性:
a、通過向用戶授予對存儲過程(而不是基於表)的訪問許可權,它們可以提供對特定數據的訪問;
b、提高代碼安全,防止 SQL注入(但未徹底解決,例如,將數據操作語言--DML,附加到輸入參數);
c、SqlParameter 類指定存儲過程參數的數據類型,作為深層次防禦性策略的一部分,可以驗證用戶提供的值類型(但也不是萬無一失,還是應該傳遞至資料庫前得到附加驗證)。
缺點就是:
1、大量的利用過程,會對伺服器壓力比較大。
『捌』 oracle 怎麼存儲過程在執行中等待5秒
dbms_lock.sleep(5000)
『玖』 Oracle中存儲過程如何設置等待特定時長之後再執行sql
oraclejob有定時執行的功能,可以在指定的時間點或每天的某個時間點自行執行任務。。
每秒鍾執行次Interval=>sysdate+1/(24*60*60),如果改成sysdate+10/(24*60*60)就是10秒鍾執行,每分鍾執行Interval=>TRUNC(sysdate,'mi')+1/(24*60)如果改成TRUNC(sysdate,'mi')+10/(24*60)就是每10分執行次每天定時執行例如:每天的凌晨1點執行Interval=>TRUNC(sysdate)+1+1/(24)。
『拾』 Oracle存儲過程長時間不跳出過程
對就是在資料庫里,你可以用pl/sql連接oracle,看到裡面有個PROCEDURE,可以在這里找到你寫的存儲過程了