sql連接的優化問題

一個簡單的sql語句:

A.select w.bzz_bm, w.jcjg_jcz as bzz_val
  from ztjc_jcjg_tb w
 where bzz_bm in (417,418)
   and jcjg_kssj = (select max(jcjg_kssj)
                      from ztjc_jcjg_tb n
                     where w.bzz_bm = n.bzz_bm
                       and n.bzz_bm in (417,418)
                       and n.jcjg_kssj <= to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss')
                       and n.jcjg_kssj > to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss') - 1 / 24);

ztjc_jcjg_tb 表裏存有至少幾千萬條的數據,結果查詢出來花了103.218秒,執行時間超過一分鐘,只是一個簡單查詢出這個表裏那兩條記錄在時間爲最接近當天8點的值。

如果改成:
B.select w.bzz_bm, w.jcjg_jcz as bzz_val
  from ztjc_jcjg_tb w
 where bzz_bm in (417,418)
   and jcjg_kssj = (select max(jcjg_kssj)
                      from ztjc_jcjg_tb n
                     where  n.bzz_bm in (417,418)
                       and n.jcjg_kssj <= to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss')
                       and n.jcjg_kssj > to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss') - 1 / 24)
執行時間絕對在1秒之內,我測試的是0.171秒。
如果改成:
C.select w.bzz_bm, w.jcjg_jcz as bzz_val
  from ztjc_jcjg_tb w
 where bzz_bm = 417
   and jcjg_kssj = (select max(jcjg_kssj)
                      from ztjc_jcjg_tb n
                     where w.bzz_bm = n.bzz_bm
                       and n.bzz_bm = 417
                       and n.jcjg_kssj <= to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss')
                       and n.jcjg_kssj > to_date('2010-12-23 08:00:00','yyyy-mm-dd hh24:mi:ss') - 1 / 24)
同樣超過一分鐘,我測試的是187.218秒,但是此時再寫w.bzz_bm = n.bzz_bm就沒有意義了,所以去掉以後測試一分鐘內,0.031秒。
如果改成:
D.select bzz_bm,max(jcjg_kssj) as kssj,jcjg_jcz
          from ztjc_jcjg_tb n
         where n.bzz_bm in (417, 418)
           and n.jcjg_kssj <=
               to_date('2010-12-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss')
           and n.jcjg_kssj >
               to_date('2010-12-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss') - 1 / 24 group by bzz_bm,jcjg_jcz
執行時間在1秒內,我測試的是0.281秒;
如果改成:
E.select w.bzz_bm, w.jcjg_jcz as bzz_val
  from ztjc_jcjg_tb w,
       (select bzz_bm, max(jcjg_kssj) as kssj
          from ztjc_jcjg_tb n
         where n.bzz_bm in (417, 418)
           and n.jcjg_kssj <=
               to_date('2010-12-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss')
           and n.jcjg_kssj >
               to_date('2010-12-23 08:00:00', 'yyyy-mm-dd hh24:mi:ss') -
               1 / 24
         group by bzz_bm) n
 where w.bzz_bm in (417, 418)
   and w.jcjg_kssj = n.kssj
   and w.bzz_bm = n.bzz_bm
執行時間又超過一分鐘,我測試的是101.344秒,但如果去掉w.bzz_bm in (417, 418)這句,執行時間在1秒內,測試爲0.015秒。
比較分析這些例子得出:影響這個SQL語句的因素有兩個,一個是in,一個是連接。其實in就是把外表和內表做hash連接。hash join處理代價非常高,是數據庫服務器內存和CPU的頭號殺手之一,尤其是涉及到分區(數據量太大導致內存不夠的情況,或者併發訪問很高導致當前處理線 程無法獲得足夠的內存,那麼數據量不是特大的情況下也可能需要進行分區)。舉例如下:
Select * from T1 where x in ( select y from T2 ),執行過程相當於select * from t1, ( select distinct y from t2 ) t2 where t1.x = t2.y;這樣表 T1 不可避免的要被完全掃描一遍,而表T1本身的數據量又是相當的大。B,D的執行速度倒是很快,可是不符合我們的規則,A,C是一個道理,加上連接後變的很慢,因爲他對兩個大數據表做的hash連接,而根據上面in的用法,相當於加上了distinct,distinct會使索引部分失效,因爲它對你要查詢的每一列進行篩選,再根據記錄重組;E之所以變的很快,是因爲內表的數據相當少,只有兩條,而在bzz_bm和jcjg_kssj上建有索引,所以直接在外表裏面查找就會變的很快。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章