需要查询的表有:
扫描批次表(scan_batch):主键(id),批次编号(batch_no)
扫描信息表(scan_info):主键(id),批次id(batch_id),Jar包id(jar_id)
Jar包信息表(jar_info):主键(id),Jar包其他信息(jar_name,jar_groupId,jar_artifactId,jar_version,jar_type,create_time)
需要查询到的记录是:
某一系统下,某一批次的扫描信息(需要展示的是Jar包的各个信息)。同时可以进行Jar包搜索
原始思路:164条记录 6.793s
SELECT DISTINCT jar_info.jar_name,
jar_info.jar_groupId,
jar_info.jar_artifactId,
jar_info.jar_version,
jar_info.jar_type,
jar_info.create_time
FROM jar_info,scan_batch
WHERE jar_info.id IN( SELECT jar_id FROM scan_info WHERE app_id=13)
AND scan_batch.batch_no='20170817165821'
and jar_info.`jar_artifactId` LIKE CONCAT('%','','%')
自己想当然的理解为先执行括号后边的sql,但事实上是子查询产生一个结果集,其中有多少记录就会和外表进行多少次比较。因此,效率十分低下。
初步优化后:164条记录 0.30s
SELECT DISTINCT jar_info.jar_name,
jar_info.jar_groupId,
jar_info.jar_artifactId,
jar_info.jar_version,
jar_info.jar_type,
jar_info.create_time
FROM jar_info,scan_batch
WHERE jar_info.id IN( SELECT jar_id FROM(SELECT jar_id FROM scan_info WHERE app_id=13) as tbt)
AND scan_batch.batch_no='20170817165821'
and jar_info.`jar_artifactId` LIKE CONCAT('%','','%')
为子查询加临时表之后,执行速度明显提高了,但是在数据库数据量增加的时候,页面响应速度依然非常慢。
优化后:164条记录 0.101s
SELECT DISTINCT ji.jar_name,
ji.jar_groupId,
ji.jar_artifactId,
ji.jar_version,
ji.jar_type,
ji.create_time
FROM jar_info ji
inner join (select si.jar_id from scan_info si
inner join scan_batch sb on si.batch_id=sb.id
where sb.batch_no='20170817103108' and si.app_id=4) tmp
on tmp.jar_id = ji.id
where ji.jar_artifactId like CONCAT('%','','%')
后来请教大佬,换了一种思路,不在用in,将in优化为连接。执行速度提高的不是一点。
总结:
1、 in可能被优化为 连接
2、 则子查询表大的用exists,子查询表小的用in
3、 in 在未被优化时,外表小,内表大时(要建临时表并排序 耗时) 效率低
4、 in在数据库数据量非常大的时候效率会很低。
另外:
5、 not in 不走索引的,因此不能用
6、 not exists走索引的。
在进行sql优化时候,很有必要用 explain 对sql语句进行性能分析,以便观察是否用到索引之类。其中各个字段的意思详见:
http://www.jb51.net/article/38357.htm
本文通过一个具体的案例,讲述了如何优化MySQL查询,从原本执行164条记录耗时6.793秒,优化到0.101秒的过程。关键在于理解IN操作的优化,以及根据内外表大小选择EXISTS或IN。总结了IN优化原则,包括在外表小、内表大时使用IN可能导致效率低下,以及NOT IN不走索引等。建议使用EXPLAIN进行SQL性能分析。
2432

被折叠的 条评论
为什么被折叠?



