同事小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;
时得到的数据为:
加上
WHERE IE.ID IS NULL
时就过滤掉了IGNORE_EMP_ID
中的数据。
修改的方法告诉了小A,过了几分钟,我就问他改的咋样,他说正在往新建的IGNORE_EMP_ID
表插数据。那好吧,我来帮忙插数据好了。
前面介绍过原来的sql里边都是一行一个数字排列的,我们把NOT IN
里边的所有ID复制出来到txt文件
然后保存文件为csv
找到刚刚保持的csv文件通过excel打开
在B1单元格输入表达式
=CONCAT("INSERT INTO IGNORE_EMP_ID(ID) VALUES (", A1, ");")
然后回车拉至最后一行,复制出B列所有sql执行即可。