可以把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;