一個執行計劃解析的小問題分析

jeanron100發表於2016-06-21
前幾天,一個開發的同學讓我幫忙做一個大查詢,給了我一個資料列表,裡面的ID有幾萬個,提供了一個SQL語句,看這情況還得我自己來解析生成相關的SQL了。
假設ID列表為:
T100
T200
T300
SQL語句為:
select peak_transaction_id,cash ,req_time  ,back_time  from peak_new.peak_detail where peak_transaction_id=?;
對我來說拼成動態SQL也是分分鐘,但是這種方式不推薦,還是推薦使用資料的結果集方式來匹配。
所以我可以根據id拼接成insert語句,或者直接使用外部表來關聯。表裡只有一個欄位id varchar2(30)
在執行語句之前我還是會照例來檢視執行計劃,如果太差我就提前想別的辦法了。
執行計劃著實讓我大跌眼鏡。一個簡單的鍵值關聯的語句,執行計劃竟然如此的查,來看看瓶頸在哪裡。

可以從謂詞資訊看出,裡面做了資料型別的轉換,根據ID這個欄位值資料型別應該是varchar2,是不需要轉換為number型別的。
但是透過執行計劃看出,內部是做了資料型別的轉換,最後這種關聯方式的消耗竟然如此驚人。
我就感覺有些蹊蹺,為什麼會有這種差別,按理來說是不需要這種型別轉換啊。
呼叫的SQL語句如下:
select TEST_transaction_id,cash ,req_time  ,back_time  from TEST_new.TEST_detail where TEST_transaction_id in (select id from tempdba.test);
發現問題的癥結在於tempdba.test不是我剛剛建立的臨時表,而是指向了一個已經存在的表。這個表的結構如下:


所以這個問題就有點意思了,tempdba.test雖然和屬主下的表test同名,但是欄位完全不同,在生成執行計劃的時候竟然還能成功,這個也讓人著實懷疑最佳化器處理執行計劃是不是也有很多不足之處。
我使用了正確的schema之後,重新生成執行計劃,這一次得到的預估結果還是在接受範圍之內。我完全可以在備庫去跑這個查詢實現目標。

那麼問題來了,是不是執行計劃對於欄位的校驗存在疏漏呢,我們來簡單測試幾個小例子。
發現在常見的表關聯中還是能夠校驗出來的。

再來看看exists的方式是否也有問題。發現也是可以檢測出來的。

所以再回頭看這個問題,就會發現在最開始的語句中。
select TEST_transaction_id,cash ,req_time  ,back_time  from TEST_new.TEST_detail where TEST_transaction_id in (select id from tempdba.test);
採用in的子查詢的時候,對於子查詢中的列可以和關聯的表不同名,我們可以取別名來達到的相容的目的,我想正是如此在執行計劃中也會弱化了這方面的檢查,嚴格來說,姑且算是一個bug吧。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23718752/viewspace-2120633/,如需轉載,請註明出處,否則將追究法律責任。

相關文章