MERGE JOIN CARTESIAN 優化…

     前兩天開發告訴我,項目數據遷移需要用到的一條sql在跑了幾分鐘後就會報錯。截圖給我是temp表空間撐滿了。sql拿過來看了一下執行計劃走了MERGE JOIN CARTESIAN。大多數情況下,笛卡爾join效率都非常差,出現錯誤的MERGE JOIN CARTESIAN原因主要是CBO估算錯誤或者sql語句忘記寫等值連接條件。此sql參與笛卡爾join的兩個結果集都非常大,所以耗盡temp表空間就不奇怪了。

     仔細看看sql,發現sql雖然關聯比較複雜,但最終的結果集才1萬多條記錄。而且一個大的業務表上寫的兩個過濾條件選擇性都還不錯,所以想到了加上合適的hint,(統計信息已經是最新的了)讓選擇性不錯的表做驅動走nest loop應該5秒內就能出結果。 

-----------------------------------------------

    select  xxx  from  ooi,oosla,ooslb
 where oosla.order_item_id = ooi.id
 and oosla.gmt_service_begin > trunc(sysdate - 2)
            or oosla.gmt_service_end > (sysdate - 3)

   and oosla.order_item_id = ooslb.order_item_id
   and ooi.is_deleted = 'n'
   and oosla.is_deleted = 'n'
   and ooi.PRODUCT_CODE IN ('pc001', 'pc005', 'pc002', 'pc006', 'pc003','pc090', 'pc091', 'pc007')      
 ORDER BY ooslb.gmt_service_begin;

------------------------------------------------

圖中標紅的兩個條件上是有索引的,而且通過過濾後記錄數值有2萬多條,所以sql改寫成:

select xxx  from ooi,
       (select *
          from oosla
         where gmt_service_begin > trunc(sysdate - 2)or gmt_service_end > (sysdate - 3))
oosla,
                  ooslb
 where oosla.order_item_id = ooi.id
   and oosla.order_item_id = ooslb.order_item_id
   and ooi.is_deleted = 'n'
   and oosla.is_deleted = 'n'
   and ooi.PRODUCT_CODE IN ('pc001', 'pc005', 'pc002', 'pc006', 'pc003','pc090', 'pc091', 'pc007')      
 ORDER BY ooslb.gmt_service_begin;

--------------------------------------------

oosla,ooi,ooslb走了nest loop,3秒不到就出來了。[轉載]MERGE <wbr>JOIN <wbr>CARTESIAN <wbr>優化一例

在寫hint的時候,還發現了和index_combine相近的一個hint:index_join ,oracle在使用多個index返回結果集的時候其實還有一種方法:and_equal 有興趣的同學可以參考lewis的文章:

http://nixforums.org/about109312-Hints-difference-between-AND_EQUAL--INDEX_JOIN-and-INDEX_.html

 

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