分享一次意外的ORACLE資料庫主機效能測試結果
最近一直在做一些ORACLE SQL效能量化方面的研究,要實現較準確的SQL效能量化很複雜,現在一直在小心推進,周末做了一下一些機器的兩個參數測試:
一個是oracle資料庫1毫秒可執行多少次記憶體hash運算操作,這個主要用於量化hash join的時間;
一個是oracle資料庫1毫秒可執行多少次記憶體排序的比較運算,這個主要用於量化order by的時間。
以下是測試結果,讓我非常意外。
以下是測試代碼,測試採用單會話sqlplus執行,因此只能衡量主機CPU單核的效能。
下面這個是hash次數的測試代碼:
declare<br /> i integer;<br /> int1 integer;<br /> t1 number;<br /> t2 number;<br /> t_all number;<br /> t_select number;<br /> execute_count number := 10;<br /> function getnumfromtimestamp(iTime timestamp) return number is<br /> Result number;<br /> v_hour number;<br /> v_minute number;<br /> v_second number;<br /> v_millisecond number;<br /> begin<br /> v_hour := EXTRACT(hour from iTime);<br /> v_minute := EXTRACT(minute from iTime);<br /> v_second := EXTRACT(second from iTime);<br /> Result := (v_hour + 1) * 3600 + (v_minute + 1) * 60 + v_second;<br /> return(Result);<br /> end;<br />begin<br /> select /*+use_hash(a,b)*/<br /> count(*)<br /> into int1<br /> from (select rownum + 20000000 rn from dual connect by rownum <= 1000000) a,<br /> (select rownum + 10000000 rn from dual connect by rownum <= 1000000) b<br /> where a.rn = b.rn;<br /> t1 := getnumfromtimestamp(systimestamp);<br /> for i in 1 .. execute_count loop<br /> select /*+use_hash(a,b)*/<br /> count(*)<br /> into int1<br /> from (select rownum + 20000000 rn<br /> from dual<br /> connect by rownum <= 1000000) a,<br /> (select rownum + 10000000 rn<br /> from dual<br /> connect by rownum <= 1000000) b<br /> where a.rn = b.rn;<br /> end loop;<br /> t2 := getnumfromtimestamp(systimestamp);<br /> t_all := t2 - t1;<br /> select count(*)<br /> into int1<br /> from (select rownum + 20000000 rn from dual connect by rownum <= 1000000);<br /> t1 := getnumfromtimestamp(systimestamp);<br /> for i in 1 .. execute_count loop<br /> select count(*)<br /> into int1<br /> from (select rownum + 20000000 rn<br /> from dual<br /> connect by rownum <= 1000000);<br /> end loop;<br /> t2 := getnumfromtimestamp(systimestamp);<br /> t_select := t2 - t1;<br /> dbms_output.put_line('hash_times:' ||<br /> trunc(1000 /<br /> ((t_all - t_select) / (2 * execute_count))));<br />end;<br />/<br />
下面這個是sort次數的測試代碼:
declare<br /> i integer;<br /> int1 integer;<br /> t1 number;<br /> t2 number;<br /> t_all number;<br /> t_select number;<br /> execute_count number := 10;<br /> function getnumfromtimestamp(iTime timestamp) return number is<br /> Result number;<br /> v_hour number;<br /> v_minute number;<br /> v_second number;<br /> v_millisecond number;<br /> begin<br /> v_hour := EXTRACT(hour from iTime);<br /> v_minute := EXTRACT(minute from iTime);<br /> v_second := EXTRACT(second from iTime);<br /> Result := (v_hour + 1) * 3600 + (v_minute + 1) * 60 + v_second;<br /> return(Result);<br /> end;<br />begin<br /> select count(*)<br /> into int1<br /> from (select rn<br /> from (select (mod(rownum, 3) * 3 - 1) * 1000000 + rownum rn<br /> from dual<br /> connect by rownum <= 1000000<br /> order by rn) c<br /> where rownum + 1 < 10000000);<br /> t1 := getnumfromtimestamp(systimestamp);<br /> for i in 1 .. execute_count loop<br /> select count(*)<br /> into int1<br /> from (select rn<br /> from (select (mod(rownum, 3) * 3 - 1) * 1000000 + rownum rn<br /> from dual<br /> connect by rownum <= 1000000<br /> order by rn) c<br /> where rownum + 1 < 10000000);<br /> end loop;<br /> t2 := getnumfromtimestamp(systimestamp);<br /> t_all := t2 - t1;<br /> select count(*)<br /> into int1<br /> from (select rn<br /> from (select (mod(rownum, 3) * 3 - 1) * 1000000 + rownum rn<br /> from dual<br /> connect by rownum <= 1000000) c<br /> where rownum + 1 < 10000000);<br /> t1 := getnumfromtimestamp(systimestamp);<br /> for i in 1 .. execute_count loop<br /> select count(*)<br /> into int1<br /> from (select rn<br /> from (select (mod(rownum, 3) * 3 - 1) * 1000000 + rownum rn<br /> from dual<br /> connect by rownum <= 1000000) c<br /> where rownum + 1 < 10000000);<br /> end loop;<br /> t2 := getnumfromtimestamp(systimestamp);<br /> t_select := t2 - t1;<br /> dbms_output.put_line('sort_times:' ||<br /> trunc(18792428 / 1000 / ((t_all - t_select))));<br />end;<br />/<br />
體會如下:
1、測試結果只是反應CPU單核的效能,並不體現主機的整體效能,主機負載對測試有一定的影響,但比較小。
2、現在PC伺服器上採用的INTEL或AMD CPU單核非常強勁,已經遠遠超過幾年前的小型機POWER5,Itanium CPU單核效能,由於沒有最新的POWER6,POWER7,所以也不好評論POWER6和POWER7的效能。
3、台式機的CPU INTEL E8400(3G)比 PC伺服器上的XEON E5520(2.26G)還強很多,這個得益於CPU主頻的提高。現在PC伺服器CPU的單核效能與台式機CPU差不多,並不像有些文章說的伺服器效能強很多,我理解是伺服器CPU穩定性更好,可擴充性更強,用普通台式機伺服器一般最多可裝2顆,但是伺服器上可裝4顆,甚至更多,這一方面是伺服器本身架構的設計支援,另一方面是伺服器CPU在多路平行處理方面考慮了更多。
4、AMD的CPU效能也非常強勁,AMD Opteron 2378(45nm) 與AMD Opteron 2356(65nm) 主頻差不多,但Cache差很多,效能高一倍,可以看出AMD的CPU效能與製造工藝和緩衝關係密切。
5、Oracle9i排序演算法的複雜度約為nlog(n),Oracle10g以後排序演算法有非常大的改進,演算法的複雜度已經遠遠小於nlog(n)。
6、小型機CPU效能已經沒有任何優勢,小型機的優勢只是
穩定性更好(我們的小型機還沒發生過異常宕機,PC伺服器有時會發生);
可維護性更好(小型機很多組件都可線上維護與升級,PC伺服器可做的很少);
可擴充性更強(小型機的CPU經常看到擴充到64顆以上,PC伺服器一般很少能上16顆)。
個人觀點:
如果你是銀行、證券類核心資料庫主機,那小型機還是有意義的,如果只是一般公司資訊化主機,那PC伺服器性價比更好,如果只是公司內部開發用伺服器,那選擇當前高效能的台式機INTEL CPU Core i7會更實用。
Oracle10g與Oracle9i相比,除了RAC外,資料庫IO管理方面沒有大的提升,但是在一些細節方面做得很優秀,如本次測試中的hash運算及排序演算法,所以如果你的主機效能瓶頸是CPU運算(非IO等待),那從Oracle9i升級至Oracle10g或11g會有一些協助。
測試結果只是反應CPU單核的效能,並不體現主機的整體效能。以上測試代碼沒有參考標準,也沒有理論基礎,只是個人隨便寫的,所以不嚴謹,但是測試結果還是有一些參考意義,拿出來與大家分享,歡迎討論。