同事小A拿來了一段sql語句問我說為什么執行特別慢,跑一次要十多分鐘。我試了一下,好家伙,最慢17分鐘。語句如下:
SELECT T.*
FROM TABLE1 T
INNER JOIN VEMPLOYEE E ON E.ID = T.EID
WHERE ...;
其中TABLE1是一個數據記錄表,VEMPLOYEE是一個員工表的視圖,我看了一下視圖定義,徹底被震驚了
CREATE OR REPLACE VIEW VEMPLOYEE AS
SELECT E.*
FROM EMPLOYEE E
WHERE E.ID NOT IN
(53237,
268710,
51529,
273123,
267052,
270336,
273121,
273134,
273132,
51643,
--后邊省略好幾百行
);
小A解釋說,客戶要求有好多地方頁面展示的時候要屏蔽一些員工,所以就直接搞了個員工視圖來做統一的過濾處理。
那么,優化開始
在sql中使用IN
或者NOT IN
的性能是非常差的,至于具體原因,好多大佬解釋的很清楚了,我就不再贅述。那么第一步,就是使用LEFT JOIN替換掉語句里邊的NOT IN
首先創建一個表IGNORE_EMP_ID
存儲需要忽略的員工ID,只有一個ID列,修改視圖創建語句如下:
CREATE OR REPLACE VIEW VEMPLOYEE AS
SELECT E.*
FROM EMPLOYEE E
LEFT JOIN IGNORE_EMP_ID IE ON IE.ID = E.ID
WHERE IE.ID IS NULL;
展示一下LEFT JOIN
替換NOT IN
的執行過程,假設EMPLOYEE表有ID為1、2、3這三個員工,需要忽略的ID有1、3這兩個
表數據
執行
SELECT *
FROM EMPLOYEE E
LEFT JOIN ON IGNORE_EMP_ID IE ON IE.ID = E.ID;
時得到的數據為:
left join結果集
加上
WHERE IE.ID IS NULL
時就過濾掉了IGNORE_EMP_ID
中的數據。
修改的方法告訴了小A,過了幾分鐘,我就問他改的咋樣,他說正在往新建的IGNORE_EMP_ID
表插數據。那好吧,我來幫忙插數據好了。
前面介紹過原來的sql里邊都是一行一個數字排列的,我們把NOT IN
里邊的所有ID復制出來到txt文件
txt
然后保存文件為csv
另存為csv
找到剛剛保持的csv文件通過excel打開
excel
在B1單元格輸入表達式
=CONCAT("INSERT INTO IGNORE_EMP_ID(ID) VALUES (", A1, ");")
然后回車拉至最后一行,復制出B列所有sql執行即可。
生成sql