Oracle調優之no_unnest和unnest用法簡介
本博客介紹Oracle SQL調優的一種常用也是很實用的方法,也即/*+no_unnest */
和/*+ unnest*/
,介紹Oracle 的 /*+unnest */
、 /*+ no_unnest */
之前,先介紹一下Hint。
Hint對於開發人員來說,可能不是很熟悉,但是對於DBA來說,Hint可是一種調優的利器,Hint 是Oracle 提供的一種SQL語法,是oracle早期因為oracle優化器還不是很完善加上去的,可以輔助oracle優化器,常用於SQL調優,通過Hint強行改變Oracle的執行計划,從而實現SQL調優
也就是說Hint語法可以人工地干預Oracle優化器選擇執行計划,當然Hint雖然很實用,但是用的不好,也必然影響SQL性能,國內DBA大牛在其博文里就有曾提到,引用其博文的觀點:
詳情可以參考作者博文:https://dbaplus.cn/news-10-669-1.html
ok,有了前面的必要知識后,可以介紹一下Oracle的Hint語法之no_unnest和unnest用法了,no_unnest、unnest顯然是一對相對的用法
- unnest:也即解嵌套,nest是嵌套的意思,也就是讓子查詢展開查詢,和外部的查詢進行關聯、合並,從而得到執行計划
- no_unnest:雙重否定表肯定,也是子查詢嵌套(nest),讓子查詢不展開,這時候子查詢往往是最后執行的,作為FILTER條件來過濾外部查詢
對於hint語法來說,形式就是/*+ .... */
的形式,所以對於這兩種嵌套和解嵌套查詢,其用法分別為/*+ no_unnest */
、/*+ unnest*/
,加在子查詢的select關鍵字后面即可,我之前博客曾經整理過Hint的常用語法,詳情參考我博客Oracle之Hint用法整理筆錄
案例記錄,ok,最近遇到一個sql查詢需要超過1分鍾的情況,因為是生產環境問題,比較緊急,業務又特別復雜,SQL很復雜,關聯了十幾張表(業務需要),如果通過改寫sql來調優,比較花時間,業務不夠熟悉的情況,所以,首先我也是先通過加必要索引的方式,檢查主鍵、外鍵是否都有索引了,索引也不能亂叫,還要分析哪些表更新比較多的,然后我是想到hint調優,雖然hint有局限性是在某些sql不改寫的情況是可以起到作用的,如果sql改變,hint語法很有可能影響SQL性能,所以使用hint調優並非上策
我遇到的sql是很復雜的,不過本文進行簡單描述,其SQL語法類似如下,省略很多的情況:
select id,....,from t1 left join t2 where t2.id in (select k from t1 where ...) ....
首先,我想到用子查詢解嵌套方式,進行改寫:
select id,....,from t1 left join t2 where t2.id in (select /*+ unnest */ k from t1 where ...) ....
然后通過執行計划查詢,性能並沒有提升,unnest是讓子查詢展開,和外部的查詢進行關聯、合並,首先t1是一張數據量很多的表,然后SQL里先left join了t1,又在子查詢里使用了t1,如果unnest的話,不是會進行自連接?所以我改成/*+ no_unnest */
,不讓子查詢展開,讓子查詢最后執行,作為一個filter條件,經過實驗,sql查詢從1分鍾以上都0點及秒
ok,說明一下,本人水平並沒有dba水平,對於SQL調優沒有豐富經驗,所以請作者可以不管我的案例,只要理解unnest和no_unnest的用法即可,sql調優是很復雜,需要很多調優經驗才可以做到游刃有余的,本博客觀點,僅代表本人觀點,因為對sql調優本沒有深入理解,所以也並沒有特別推崇使用unnest或者no_unnest,這兩種用法具體在什么環境使用適宜?在網上也沒有找到特別明確的說明,所以遇到sql性能問題,通過分析執行計划是最有用的
附錄:
- SQL優化:一篇文章說清楚Oracle Hint的正確用法:https://dbaplus.cn/news-10-669-1.html
- 性能優化之查詢轉換 子查詢類:https://chuansongme.com/n/1394222147942
- 解決CBO的SQL優化問題(圖文詳解):https://www.php.cn/mysql-tutorials-360101.html
- Oracle里的查詢轉換:https://www.linuxidc.com/Linux/2019-03/157808.html