oracle數(shù)據(jù)庫限制返回的記錄數(shù)問題
今天yxg提了一張bug單中提到oracle的環(huán)境下告警查詢非常慢,連上去看了一下發(fā)現(xiàn)是非常慢(十多秒鐘),開始懷疑是setMaxRow沒有生效,導致進行了全表查詢,但是在頁面確認返回的結(jié)果確實是set過的500條,但是如果在語句里直接加入rownum<500不用QueryHelper.setMaxRow方法來限制查詢條數(shù)的時候查詢速度確是正常的(毫秒級),是不是jdbc的setMaxRow這個方法在性能上有些不足?
re:
setMaxRow的作用是限制最終的返回記錄數(shù),這個限制返回和sql執(zhí)行的速度是基本沒有什么關(guān)系。
你需要了解一下sql的運行機制,你可以set showplan on來看看sql的執(zhí)行計劃。
上面紅色的最終意思是:數(shù)據(jù)庫已經(jīng)處理好返回的結(jié)果,然后從這些結(jié)構(gòu)中獲取指定的返回記錄數(shù)。
特別是一些帶有order by的操作,如果沒有用到索引,則需要將查詢結(jié)果放到臨時表中進行排序,然后再從排序結(jié)果中返回指定的記錄數(shù)。這個創(chuàng)建臨時表和排序的過程也非常消耗數(shù)據(jù)庫的cpu的。
setMaxRow作用主要是避免應用服務器這段需要處理過多的記錄而導致出現(xiàn)IO的性能問題。
我們的web開發(fā)主要都是圍繞數(shù)據(jù)庫的開發(fā),sql的性能直接影響系統(tǒng)的穩(wěn)定性。sql的編寫通常都需要一些經(jīng)驗和技巧的,關(guān)于這塊開發(fā)中心可以考慮進行一次培訓。
re:
我覺得這個接口只能限制你返回的數(shù)據(jù),而不能限制你查出來多少數(shù)據(jù),限制查出來多少條還是要程序自己控制。
想在這個接口里面控制查出來的結(jié)果集有難度。
以oracle為例,我就有個深刻教訓。
從97接口表中查詢1000條待處理數(shù)據(jù),按照SO_NBR,ACT_TYPE排序,原來是這樣寫的
select * from interface_97 where STS='D' and rownum<=1000 order by SO_NBR,ACT_TYPE
這個語句是在oracle里是有問題的,雖然是排序了,也只返回了1000條,但是SO_NBR不連續(xù)了,因為oracle只是從STS='D'的數(shù)據(jù)中抽取了1000條進行排序(抽取的規(guī)則不詳,雖然大多數(shù)情況下沒問題)
后來改成這樣就沒問題了
select * from (
select * from interface_97
where STS='D' order by SO_NBR,ACT_TYPE
)
where rownum<=1000
order by rownum asc
上面舉的例子只是想說明,要想在setMaxRow里面把你想做的都做了,實現(xiàn)起來肯定有難度,而且可能和你的預期不一致,所以最好還是在你的代碼中控制數(shù)據(jù)量。
re:
嗯,這個讓 QueryHelper 來加或替換 set rowcount 或 rownum 或 top,隨意性太大,甚至象魏巍這個例子一樣,導致結(jié)果可能不是你想要的。
在DBA中,限制查詢數(shù)據(jù)的返回條數(shù),大家都寫死 select maxrow=1000, * from table
然后 DBA對應 Sybase翻譯成 set rowcount 1000,Oralce翻譯成 rownum < 5000,自定義的一套SQL規(guī)則。比較土 :)
QueryHelper,僅僅是在 java.sql.* 上簡單的包裝了一層,做了日志和時間統(tǒng)計過程。和其名字相稱,僅僅是一個簡單的helper。
大家有沒有什么比較好的,又不是太重量級的咚咚,來屏蔽這種數(shù)據(jù)庫層面的差異?
做出來show show,大家都覺得好的話,肯定會加到openEAP上去。
呵呵,openEAP是大家的EAP,是open的....
就如老湯說的,目前用QueryHelper這個層面,很難把數(shù)據(jù)庫的SQL差異給屏蔽掉:
如很常用的日期類型,很多查詢中都會用到,如果不加 todate 函數(shù),Oracle不會執(zhí)行的,而Sybase則不需要。
Sybase用條件查詢有 case,Oracle用 decode ...