今天收到一個同事的求助,說有一個SQL跑了一個多小時沒有結果。我看了看,這個SQL是這樣的(隱藏了敏感信息):
SELECT 電話號碼, 列2, 列3, MAX(STARTTIME), FLAG FROM 表1 T1 WHERE FLAG = '0' AND 電話號碼 NOT IN (SELECT 電話號碼 FROM 表2 T2) GROUP BY 電話號碼, 列2, 列3, FLAG;
我首先查看了兩個表的數據量,表1有將近300萬條,表2有不到10萬條記錄。並不是很大的數據。於是我關注到了not in,這個語句是幾乎所有的優化指南上都明確說了要避免的語句。於是我就把這句改了,改成了not exists:
SELECT 電話號碼, 列2, 列3, MAX(STARTTIME), FLAG FROM 表1_新 T1 WHERE FLAG = '0' AND NOT EXISTS (SELECT 電話號碼 FROM 表2 T2 WHERE T1.電話號碼 = T2.電話號碼) GROUP BY 電話號碼, 列2, 列3, FLAG;
但是COST僅僅降低到了原來的五分之一,這遠遠不是我需要的。我需要的是質一樣的飛躍。
我看了一下原本SQL的執行計划:
我發現全表掃描耗用很大。查詢一下數據,發現這是一張客戶信息表,所有人的電話號碼都是不同的,因此我想到了將這個表改成一個哈希分區表。至於為什么會想到哈希分區表,參考我以前寫過的:http://www.cnblogs.com/wingsless/archive/2012/09/28/2707661.html。
我建立了一張哈希分區表:表1_新。
這個時候我用剛才改的語句,然后看看執行計划:
這個效果就非常好了,36847的COST和2684K的COST比起來簡直是天壤之別。實際測試一下,查詢出所有的數據僅僅需要55秒。
如果不用not exists,在哈希分區表上用原來的SQL查查,執行計划是這樣的:
可以看到COST會有下降,但是僅僅是一半左右,這也不是優化所要達到的目的。
其實這次SQL優化的主要在於使用了not exists。因為在三個執行計划中,最開始的對表1或者表1_新的掃描,COST都不到20000,而且很接近,因此哈希分區應該並不是提升效率的關鍵。至於效率為什么提高,這句是關鍵:access("T1"."電話號碼"="T2"."電話號碼")。關於not in和not exists的優劣區別,今天太晚了,周末再好好寫寫吧。
有幾次同事問我怎么去優化?其實優化,我覺得並沒有什么技巧,應該就和踢足球一樣,沒有什么戰無不勝的踢法,只有對場上局面冷靜的分析,隨時調整戰法,才能無往而不利,這樣才是好的教練,這應該就是穆里尼奧的本事。優化也是這樣的,不同的SQL有不同的優化方法,冷靜的分析,運用自己學過的技術,總能把調優做的很好。