Mysql中in和not in子查询的优化

可以把in改为关联查询,也可以把它改成exists

如需求:查询所有部门的所有员工:

#in子查询
SELECT * FROM tb_user WHERE dept_id IN (SELECT id FROM tb_dept);

#这样写等价于:

#先查询部门表
SELECT id FROM tb_dept

#再由部门dept_id,查询tb_user的员工
SELECT * FROM tb_user u,tb_dept d WHERE u.dept_id = d.id

not in使用 not exists 进行替代

# 比如语句
SELECT * FROM tb_case WHERE SYMBOL!= 9 AND 
CASENO NOT IN (SELECT CASENO FROM tb_carout WHERE STATUS=25 AND SYMBOL!=9)


# 该语句之所以效率低下,很大一部分原因是Not IN不走索引。
# 1:可以优化成这样
SELECT COUNT(*) FROM tb_case a WHERE SYMBOL!= 9 and 
NOT exists 
(SELECT CASENO FROM tb_carout b WHERE a.caseno=b.caseno and STATUS=25 AND SYMBOL!=9)


# 也可以使用left join进行优化
SELECT * FROM tb_case a 
left join 
    tb_carout b 
    on a.caseno=b.caseno and b.STATUS=25 and b.SYMBOL!=9 where b.caseno is null and a.symbol!=9 

循环嵌套查询执行原理
循环由外向内,外层循环执行一次,内层循环则需要完整的执行一次,内层执行执行完后返回执行结果,外层循环继续执行,直到外层循环完全执行完成

循环优化策略
有了上面的执行原理的说明,我们明白了一个道理:内层循环次数的多少不会影响到外层的次数,但是外层循环的次数直接会影响到内层循环的次数,外层循环每多一次,内层循环就需要多完整的一次循环,所以我们优化的目标其实就是使外层的循环次数尽量少,总结来说:小表驱动大表。小表就是外层循环,大表就是内层循环,也就是尽量减少外层循环的次数

IN和Exists的区别

exists : 外表先进行循环查询,将查询结果放入exists的子查询中进行条件验证,确定外层查询数据是否保留

in : 先查询内表,将内表的查询结果当做条件提供给外表查询语句进行比较

结论:
 

外层小表,内层大表(或者将sql从左到由来看:左面小表,右边大表): exists 比 in 的效率高
外层大表,内层小表(或者将sql从左到由来看:左面大表,右边小表): in 比 exists 的效率高
 

比如

SELECT
	TB_CASE.CASENO AS CASENO,
	TB_CASE.LAWGROUP AS LAWGROUP,
	S1.ROLE_NAME AS LGNAME,
	TB_CASE.CARPARK AS CARPARK,
	S2.ROLE_NAME AS CARPARKNAME,
	TB_CASE.LAWTIME AS LAWTIME,
	TB_CASE.CARTYPE AS CARTYPE,
	TB_CASE.CARNO AS CARNO,
	TB_CASE.STATUS AS STATUS,
	TB_CASE.IS_CLONE AS IS_CLONE,
	TB_CASE.BCFS AS BCFS 
FROM
	TB_CASE,
	SYS_ROLE S1,
	SYS_ROLE S2 
WHERE
	((
			NOT (
				TB_CASE.CASENO IN (
				SELECT
					TB_CAROUT.CASENO 
				FROM
					TB_CAROUT 
				WHERE
					((
							TB_CAROUT.STATUS = '25' 
							) 
					AND ( TB_CAROUT.SYMBOL <> 9 ))))) 
	AND ( TB_CASE.LAWGROUP = S1.ROLE_ID ) 
	AND ( TB_CASE.CARPARK = S2.ROLE_ID ));

他的left join写法

SELECT
	T1.CASENO AS CASENO,
	T1.LAWGROUP AS LAWGROUP,
	S1.ROLE_NAME AS LGNAME,
	T1.CARPARK AS CARPARK,
	S2.ROLE_NAME AS CARPARKNAME,
	T1.LAWTIME AS LAWTIME,
	T1.CARTYPE AS CARTYPE,
	T1.CARNO AS CARNO,
	T1.STATUS AS STATUS,
	T1.IS_CLONE AS IS_CLONE,
	T1.BCFS AS BCFS 
FROM
	TB_CASE T1
	LEFT JOIN TB_CAROUT T2 ON T1.CASENO = T2.CASENO 
	    AND T2.STATUS = '25' 
	    AND T2.SYMBOL != 9
	LEFT JOIN SYS_ROLE S1 ON T1.LAWGROUP = S1.ROLE_ID
	LEFT JOIN SYS_ROLE S2 ON T1.CARPARK = S2.ROLE_ID 
WHERE
	T2.CASENO IS NULL;

你可能感兴趣的:(数据库,1024程序员节,mysql)