Ⅰ 單獨執行很快,為什麼在存儲過程裡面執行很慢
慢的原因是你在對List的循環中使用了List的get函數.
典型的"Shlemiel噴塗演算法",所以越跑越慢啊.
List里是一個鏈表,get方法會從頭一個個地數,越到後面,數的時間就越長.所以會慢..
你應該修改方式,用下面的方法進行循環:
for(Iterator it = list.iterator(); it.hasNext() ;){
Map map = (Map)it.next();
// ...
}
Ⅱ 為什麼存儲過程執行速度比普通的SQL快而且減少網路流量
存儲過程所以快是因為他是預先編譯的,當然節省了編譯的時間。減少網路流量是指減少與客戶端之間的交互,在伺服器上執行運算,最後只把結果反給客戶端,所以流量少。
比如你查詢個內容,需要先查一個表,根據結果再查另外一個表。不用存儲過程你怎麼做呢?自然是先讀出那個表的內容來,然後在asp/asp.net/php里,用代碼生成一個語句再去查詢,這樣要往復2,3次。而用存儲過程就可以直接在伺服器上運算,只要一次來回就ok了,自然網路流量就減少
因為在存儲過程中的SQL語句是已經經過了語法檢查和編譯的,可以直接執行;而SQL總要先進行語法解析和編譯才能執行。另外對於網路執行的話,執行相同的任務,客戶端調用存儲過程的代碼傳輸量和直接執行SQL語句相比也要更少。
Ⅲ 為什麼存儲過程比直接執行sql語句要慢良多
很較著,是參數嗅探詢題。
Ⅳ 為什麼這個存儲過程執行的性能這么差
大家都在討論關於資料庫優化方面的東東,剛好參與開發了一個數據倉庫方面的項目,以下的一點東西算是資料庫優化方面的學習 實戰的一些心得體會了,拿出來大家共享。歡迎批評指正阿!
SQL語句:
是對資料庫(數據)進行操作的惟一途徑;
消耗了70%~90%的資料庫資源;獨立於程序設計邏輯,相對於對程序源代碼的優化,對SQL語句的優化在時間成本和風險上的代價都很低;
可以有不同的寫法;易學,難精通。
SQL優化:
固定的SQL書寫習慣,相同的查詢盡量保持相同,存儲過程的效率較高。
應該編寫與其格式一致的語句,包括字母的大小寫、標點符號、換行的位置等都要一致
ORACLE優化器:
在任何可能的時候都會對表達式進行評估,並且把特定的語法結構轉換成等價的結構,這么做的原因是
要麼結果表達式能夠比源表達式具有更快的速度
要麼源表達式只是結果表達式的一個等價語義結構
不同的SQL結構有時具有同樣的操作(例如:= ANY (subquery) and IN (subquery)),ORACLE會把他們映射到一個單一的語義結構。
1 常量優化:
常量的計算是在語句被優化時一次性完成,而不是在每次執行時。下面是檢索月薪大於2000的的表達式:
sal > 24000/12
sal > 2000
sal*12 > 24000
如果SQL語句包括第一種情況,優化器會簡單地把它轉變成第二種。
優化器不會簡化跨越比較符的表達式,例如第三條語句,鑒於此,應盡量寫用常量跟欄位比較檢索的表達式,而不要將欄位置於表達式當中。否則沒有辦法優化,比如如果sal上有索引,第一和第二就可以使用,第三就難以使用。
2 操作符優化:
優化器把使用LIKE操作符和一個沒有通配符的表達式組成的檢索表達式轉換為一個「=」操作符表達式。
例如:優化器會把表達式ename LIKE 'SMITH'轉換為ename = 'SMITH'
優化器只能轉換涉及到可變長數據類型的表達式,前一個例子中,如果ENAME欄位的類型是CHAR(10), 那麼優化器將不做任何轉換。
一般來講LIKE比較難以優化。
其中:
~~ IN 操作符優化:
優化器把使用IN比較符的檢索表達式替換為等價的使用「=」和「OR」操作符的檢索表達式。
例如,優化器會把表達式ename IN ('SMITH','KING','JONES')替換為
ename = 'SMITH' OR ename = 'KING' OR ename = 'JONES『
~~ ANY和SOME 操作符優化:
優化器將跟隨值列表的ANY和SOME檢索條件用等價的同等操作符和「OR」組成的表達式替換。
例如,優化器將如下所示的第一條語句用第二條語句替換:
sal > ANY (:first_sal, :second_sal)
sal > :first_sal OR sal > :second_sal
優化器將跟隨子查詢的ANY和SOME檢索條件轉換成由「EXISTS」和一個相應的子查詢組成的檢索表達式。
例如,優化器將如下所示的第一條語句用第二條語句替換:
x > ANY (SELECT sal FROM emp WHERE job = 'ANALYST')
EXISTS (SELECT sal FROM emp WHERE job = 'ANALYST' AND x > sal)
~~ ALL操作符優化:
優化器將跟隨值列表的ALL操作符用等價的「=」和「AND」組成的表達式替換。例如:
sal > ALL (:first_sal, :second_sal)表達式會被替換為:
sal > :first_sal AND sal > :second_sal
對於跟隨子查詢的ALL表達式,優化器用ANY和另外一個合適的比較符組成的表達式替換。例如
x > ALL (SELECT sal FROM emp WHERE deptno = 10) 替換為:
NOT (x <= ANY (SELECT sal FROM emp WHERE deptno = 10))
接下來優化器會把第二個表達式適用ANY表達式的轉換規則轉換為下面的表達式:
NOT EXISTS (SELECT sal FROM emp WHERE deptno = 10 AND x <= sal)
~~ BETWEEN 操作符優化:
優化器總是用「>=」和「<=」比較符來等價的代替BETWEEN操作符。
例如:優化器會把表達式sal BETWEEN 2000 AND 3000用sal >= 2000 AND sal <= 3000來代替。
~~ NOT 操作符優化:
優化器總是試圖簡化檢索條件以消除「NOT」邏輯操作符的影響,這將涉及到「NOT」操作符的消除以及代以相應的比較運算符。
例如,優化器將下面的第一條語句用第二條語句代替:
NOT deptno = (SELECT deptno FROM emp WHERE ename = 'TAYLOR')
deptno <> (SELECT deptno FROM emp WHERE ename = 'TAYLOR')
通常情況下一個含有NOT操作符的語句有很多不同的寫法,優化器的轉換原則是使「NOT」操作符後邊的子句盡可能的簡單,即使可能會使結果表達式包含了更多的「NOT」操作符。
例如,優化器將如下所示的第一條語句用第二條語句代替:
NOT (sal < 1000 OR comm IS NULL)
NOT sal < 1000 AND comm IS NOT NULL sal >= 1000 AND comm IS NOT NULL
如何編寫高效的SQL:
當然要考慮sql常量的優化和操作符的優化啦,另外,還需要:
1 合理的索引設計:
例:表record有620000行,試看在不同的索引下,下面幾個SQL的運行情況:
語句A
SELECT count(*) FROM record
WHERE date >'19991201' and date < '19991214『 and amount >2000
語句B
SELECT count(*) FROM record
WHERE date >'19990901' and place IN ('BJ','SH')
語句C
SELECT date,sum(amount) FROM record
group by date
1 在date上建有一個非聚集索引
A:(25秒)
B:(27秒)
C:(55秒)
分析:
date上有大量的重復值,在非聚集索引下,數據在物理上隨機存放在數據頁上,在范圍查找時,必須執行一次表掃描才能找到這一范圍內的全部行。
2 在date上的一個聚集索引
A:(14秒)
B:(14秒)
C:(28秒)
分析:
在聚集索引下,數據在物理上按順序在數據頁上,重復值也排列在一起,因而在范圍查找時,可以先找到這個范圍的起末點,且只在這個范圍內掃描數據頁,避免了大范圍掃描,提高了查詢速度。
3 在place,date,amount上的組合索引
A:(26秒)
C:(27秒)
B:(< 1秒)
分析:
這是一個不很合理的組合索引,因為它的前導列是place,第一和第二條SQL沒有引用place,因此也沒有利用上索引;第三個SQL使用了place,且引用的所有列都包含在組合索引中,形成了索引覆蓋,所以它的速度是非常快的。
4 在date,place,amount上的組合索引
A: (< 1秒)
B:(< 1秒)
C:(11秒)
分析:
這是一個合理的組合索引。它將date作為前導列,使每個SQL都可以利用索引,並且在第一和第三個SQL中形成了索引覆蓋,因而性能達到了最優。
總結1
預設情況下建立的索引是非聚集索引,但有時它並不是最佳的;合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:
有大量重復值、且經常有范圍查詢(between, >,< ,>=,< =)和order by、group by發生的列,考慮建立聚集索引;
經 常同時存取多列,且每列都含有重復值可考慮建立組合索引;在條件表達式中經常用到的不同值較多的列上建立檢索,在不同值少的列上不要建立索引。比如在雇員 表的「性別」列上只有「男」與「女」兩個不同值,因此就無必要建立索引。如果建立索引不但不會提高查詢效率,反而會嚴重降低更新速度。
組合索引要盡量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。
2 避免使用不兼容的數據類型:
例如float和INt、char和varchar、bINary和varbINary是不兼容的。數據類型的不兼容可能使優化器無法執行一些本來可以進行的優化操作。例如:
SELECT name FROM employee WHERE salary > 60000
在這條語句中,如salary欄位是money型的,則優化器很難對其進行優化,因為60000是個整型數。我們應當在編程時將整型轉化成為錢幣型,而不要等到運行時轉化。
3 IS NULL 與IS NOT NULL:
不 能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列就會從索引中排 除。也就是說如果某列存在空值,即使對該列建索引也不會提高性能。任何在WHERE子句中使用is null或is not null的語句優化器是不允 許使用索引的。
4 IN和EXISTS:
EXISTS要遠比IN的效率高。裡面關繫到full table scan和range scan。幾乎將所有的IN操作符子查詢改寫為使用EXISTS的子查詢。
例子:
語句1
SELECT dname, deptno FROM dept
WHERE deptno NOT IN
(SELECT deptno FROM emp);
語句2
SELECT dname, deptno FROM dept
WHERE NOT EXISTS
(SELECT deptno FROM emp
WHERE dept.deptno = emp.deptno);
明顯的,2要比1的執行性能好很多
因為1中對emp進行了full table scan,這是很浪費時間的操作。而且1中沒有用到emp的INdex,
因為沒有WHERE子句。而2中的語句對emp進行的是range scan。
5 IN、OR子句常會使用工作表,使索引失效:
如果不產生大量重復值,可以考慮把子句拆開。拆開的子句中應該包含索引。
6 避免或簡化排序:
應當簡化或避免對大型表進行重復的排序。當能夠利用索引自動以適當的次序產生輸出時,優化器就避免了排序的步驟。以下是一些影響因素:
索引中不包括一個或幾個待排序的列;
group by或order by子句中列的次序與索引的次序不一樣;
排序的列來自不同的表。
為了避免不必要的排序,就要正確地增建索引,合理地合並資料庫表(盡管有時可能影響表的規范化,但相對於效率的提高是值得的)。如果排序不可避免,那麼應當試圖簡化它,如縮小排序的列的范圍等。
7 消除對大型錶行數據的順序存取:
在 嵌套查詢中,對表的順序存取對查詢效率可能產生致命的影響。比如採用順序存取策略,一個嵌套3層的查詢,如果每層都查詢1000行,那麼這個查詢就要查詢 10億行數據。避免這種情況的主要方法就是對連接的列進行索引。例如,兩個表:學生表(學號、姓名、年齡??)和選課表(學號、課程號、成績)。如果兩個 表要做連接,就要在「學號」這個連接欄位上建立索引。
還可以使用並集來避免順序存取。盡管在所有的檢查列上都有索引,但某些形式的WHERE子句強迫優化器使用順序存取。下面的查詢將強迫對orders表執行順序操作:
SELECT * FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
雖然在customer_num和order_num上建有索引,但是在上面的語句中優化器還是使用順序存取路徑掃描整個表。因為這個語句要檢索的是分離的行的集合,所以應該改為如下語句:
SELECT * FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT * FROM orders WHERE order_num=1008
這樣就能利用索引路徑處理查詢。
8 避免相關子查詢:
一個列的標簽同時在主查詢和WHERE子句中的查詢中出現,那麼很可能當主查詢中的列值改變之後,子查詢必須重新查詢一次。查詢嵌套層次越多,效率越低,因此應當盡量避免子查詢。如果子查詢不可避免,那麼要在子查詢中過濾掉盡可能多的行。
9 避免困難的正規表達式:
MATCHES和LIKE關鍵字支持通配符匹配,技術上叫正規表達式。但這種匹配特別耗費時間。例如:SELECT * FROM customer WHERE zipcode LIKE 「98_ _ _」
即使在zipcode欄位上建立了索引,在這種情況下也還是採用順序掃描的方式。如果把語句改為SELECT * FROM customer WHERE zipcode >「98000」,在執行查詢時就會利用索引來查詢,顯然會大大提高速度。
另外,還要避免非開始的子串。例如語句:SELECT * FROM customer WHERE zipcode[2,3] >「80」,在WHERE子句中採用了非開始子串,因而這個語句也不會使用索引。
10 不充份的連接條件:
例:表card有7896行,在card_no上有一個非聚集索引,表account有191122行,在account_no上有一個非聚集索引,試看在不同的表連接條件下,兩個SQL的執行情況:
SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no
(20秒)
將SQL改為:
SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no and a.account_no=b.account_no
(< 1秒)
分析:
在第一個連接條件下,最佳查詢方案是將account作外層表,card作內層表,利用card上的索引,其I/O次數可由以下公式估算為:
外層表account上的22541頁 (外層表account的191122行*內層表card上對應外層表第一行所要查找的3頁)=595907次I/O
在第二個連接條件下,最佳查詢方案是將card作外層表,account作內層表,利用account上的索引,其I/O次數可由以下公式估算為:
外層表card上的1944頁 (外層表card的7896行*內層表account上對應外層表每一行所要查找的4頁)= 33528次I/O
可見,只有充份的連接條件,真正的最佳方案才會被執行。
多表操作在被實際執行前,查詢優化器會根據連接條件,列出幾組可能的連接方案並從中找出系統開銷最小的最佳方案。連接條件要充份考慮帶有索引的表、行數多的表;內外表的選擇可由公式:外層表中的匹配行數*內層表中每一次查找的次數確定,乘積最小為最佳方案。
不可優化的WHERE子句
例1
下列SQL條件語句中的列都建有恰當的索引,但執行速度卻非常慢:
SELECT * FROM record WHERE substrINg(card_no,1,4)='5378'
(13秒)
SELECT * FROM record WHERE amount/30< 1000
(11秒)
SELECT * FROM record WHERE convert(char(10),date,112)='19991201'
(10秒)
分析:
WHERE子句中對列的任何操作結果都是在SQL運行時逐列計算得到的,因此它不得不進行表搜索,而沒有使用該列上面的索引;如果這些結果在查詢編譯時就能得到,那麼就可以被SQL優化器優化,使用索引,避免表搜索,因此將SQL重寫成下面這樣:
SELECT * FROM record WHERE card_no like '5378%'
(< 1秒)
SELECT * FROM record WHERE amount< 1000*30
(< 1秒)
SELECT * FROM record WHERE date= '1999/12/01'
(< 1秒)
11 存儲過程中,採用臨時表優化查詢:
例
1.從parven表中按vendor_num的次序讀數據:
SELECT part_num,vendor_num,price FROM parven ORDER BY vendor_num
INTO temp pv_by_vn
這個語句順序讀parven(50頁),寫一個臨時表(50頁),並排序。假定排序的開銷為200頁,總共是300頁。
2.把臨時表和vendor表連接,把結果輸出到一個臨時表,並按part_num排序:
SELECT pv_by_vn,* vendor.vendor_num FROM pv_by_vn,vendor
WHERE pv_by_vn.vendor_num=vendor.vendor_num
ORDER BY pv_by_vn.part_num
INTO TMP pvvn_by_pn
DROP TABLE pv_by_vn
這 個查詢讀取pv_by_vn(50頁),它通過索引存取vendor表1.5萬次,但由於按vendor_num次序排列,實際上只是通過索引順序地讀 vendor表(40+2=42頁),輸出的表每頁約95行,共160頁。寫並存取這些頁引發5*160=800次的讀寫,索引共讀寫892頁。
3.把輸出和part連接得到最後的結果:
SELECT pvvn_by_pn.*,part.part_desc FROM pvvn_by_pn,part
WHERE pvvn_by_pn.part_num=part.part_num
DROP TABLE pvvn_by_pn
這樣,查詢順序地讀pvvn_by_pn(160頁),通過索引讀part表1.5萬次,由於建有索引,所以實際上進行1772次磁碟讀寫,優化比例為30∶1。
Ⅳ 存儲過程比SQL語句慢的問題,痛苦中.....
1首先存儲過程是預編譯,按理說應該會比程序運行的語句效率高,如果時間反而長的話,可能是統計信息沒有及時更新導致優化器給存儲過程與單語句生成了不同的查詢計劃,而用片面的統計信息生成的查詢計劃會導致索引利用率低效,試試更新統計信息或者重建/重組索引
2一次提交查詢6、7百次?這樣的系統我還未見過,如果可以的話,現將需要的表數據緩存到伺服器或者本地內存中,在內存中進行數據的操作,當然存儲過程對復雜的查詢會有一定的優化效果的
Ⅵ 同樣一個存儲過程,為什麼第一次快,第二次就很慢
sql是高級語言,資料庫系統執行sql之前要將sql語句進行解析(相當於編譯),這個過程叫硬解析;資料庫系統每次執行sql之前都會檢查共享池中是不是存在已經解析過的語句,如果有就拿來直接用,這叫軟結息。軟解析比硬解析效率高,這是影響因素之一;
二、第一次執行可能沒有走索引,第二次執行使用第一次執行的執行計劃
三、看你的存儲過程做了些什麼,有可能第一次把活幹完了,導致第二次執行沒什麼活干
以上回答基於oracle體系結構
Ⅶ oracle存儲過程執行速度很慢是什麼原因
原因很多,只能具體問題具體分析,一般來說,執行速度慢的原因有:
1、sql語句效率太低
2、循環次數太多導致慢
3、數據量過於龐大,導致統計時速度慢等。
Ⅷ 同樣一個存儲過程有時候運行特別慢,為什麼解決辦法
數據量,並發行都是影響數據執行過程的因素,可以用執行過程監測
Ⅸ 哪位高人說說 Oracle 11g 編譯存儲過程非常緩慢是怎麼回事
客戶端向伺服器端的網路?感覺也正好是忙的時候你的資料庫編譯。 。 。
Ⅹ 為什麼存儲過程比直接執行sql語句要慢很多
因為存儲過程只需要編譯一次
之後運行這個存儲過程就不需要在編譯了
但是SQL語句每次都要編譯
在程序里
使用存儲過程
可以減少網路傳輸量