目标
分析子查询时对索引的利用
例子
- 还是tbl_trx_order订单表,和另外一张支付订单表tbl_pay_order, PAY_EXTERNAL_NO 表中CREATE_TIME是索引字段, tbl_trx_order 表中tbl_trx_order 是索引字段,sql如下,此时会用索引吗
explain SELECT * FROM tbl_trx_order where PAY_EXTERNAL_NO in ( select PAY_EXTERNAL_NO from tbl_pay_order where CREATE_TIME >'2017-11-13 15:00:27' )
- 将in改为=号,此时会用索引吗
explain SELECT * FROM tbl_trx_order where PAY_EXTERNAL_NO = ( select PAY_EXTERNAL_NO from tbl_pay_order where CREATE_TIME ='2018-07-05 11:19:25' )
分析
网上有很多博客说,mysql的in是不会使用索引的,亲测了下,这么说不完全正确.
看下上面两个sql的执行计划


显然,sql1中in的方式我们并没有用到索引,而子查询=到方式,索引是生效的.但其实也有特殊情况,如过此时我的tbl_pay_order子表的pay_external_no也是有索引的,再来看下执行计划

发现此时查询tbl_trx_order是会用到从tbl_pay_order查询出的pay_external_No索引进行索引匹配.所以这个时候索引是生效的.
但下面我们把sql1中的时间改下,再来试一下
explain SELECT * from tbl_trx_order where PAY_EXTERNAL_NO in ( select PAY_EXTERNAL_NO from tbl_pay_order where CREATE_TIME >'2017-10-13 15:00:27' )
执行计划如下

我们发现,上面出现的索引生效又突然失效了!!!这是因为mysql对于not in ,!=这种肯定是没有索引,但>、<这种范围型的索引生效情况,mysql会自动进行优化,如果使用索引比查全表节省时间,mysql会去使用索引,否则这种情况不会用索引.
另外,我们发现子表中的索引失效的时候,外层表的索引一样会联动失效.综合考虑,in最好少用.
网友评论