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