使用過oracle或者其他關系數據庫的dba或者開發人員都有這樣的經驗,在子查詢上都認為數據庫已經做過優化,能夠很好的選擇驅動表執行,然后在把該經驗移植到mysql數據庫上,但是不幸的是,mysql在子查詢的處理上有可能會讓你大失所望,在我們的生產系統上就由于碰到了這個問題:
select??i_id,?sum(i_sell)?as?i_sell from?table_data where?i_id?in?(select?i_id?from?table_data?where?Gmt_create?>=?‘2011-10-07?00:00:00’) group?by?i_id;
(備注:sql的業務邏輯可以打個比方:先查詢出10-07號新賣出的100本書,然后在查詢這新賣出的100本書在全年的銷量情況)。
這條sql之所以出現的性能問題在于mysql優化器在處理子查詢的弱點,mysql優化器在處理子查詢的時候,會將將子查詢改寫。通常情況下,我們希望由內到外,先完成子查詢的結果,然后在用子查詢來驅動外查詢的表,完成查詢;但是mysql處理為將會先掃描外面表中的所有數據,每條數據將會傳到子查詢中與子查詢關聯,如果外表很大的話,那么性能上將會出現問題;
針對上面的查詢,由于table_data這張表的數據有70W的數據,同時子查詢中的數據較多,有大量是重復的,這樣就需要關聯近70W次,大量的關聯導致這條sql執行了幾個小時也沒有執行完成,所以我們需要改寫sql:
SELECT?t2.i_id,?SUM(t2.i_sell)?AS?sold FROM?(SELECT?distinct?i_id?FROM?table_data WHERE?gmt_create?>=?‘2011-10-07?00:00:00’)?t1,??table_data?t2 WHERE?t1.i_id?=?t2.i_id?GROUP?BY?t2.i_id;
我們將子查詢改為了關聯,同時在子查詢中加上distinct,減少t1關聯t2的次數;
改造后,sql的執行時間降到100ms以內。?
? 版權聲明
文章版權歸作者所有,未經允許請勿轉載。
THE END