(1)子查询是如何执行的?
select from t1 where x1= (select x1 from t2 where id=xxx ) 这是一个典型的子查询
在执行上面的SQL语句是,其实会被拆分成两个步骤,第一个步骤先执行子查询,也就是 select x1 from t2 where id=xxx ,直接根据主键定位出一条数据的x1字段值,接着再执行select from t1 where x1=子查询结果值,这个SQL 语句。
另外一种子查询:
select * from t1 where x1=(select x1 from t2 where t1.x2=t2.x2)
子查询里的where条件依赖于t1表的字段值,所以这种查询效率很低下,需要遍历t1表里每一条数据,对每一条数据取出x2字段值,放到子查询里去执行,找出t2表的某条数据的x1字段值,再放到外层去判断,是否符合跟t1表的x1字段匹配。
(2)IN语句结合子查询的一个优化手段:
select from t1 where x1 in (select x2 from t2 where x3=xxx)
这个SQL语句典型的是子查询运用,子查询查一批结果,然后判断t1表那些数据的x1值在这个结果集里。这个可能大家会认为先执行子查询,然后对t1表再进行全表扫描,判断每条数据是否在这个子查询的结果集里。
但是这种方式其实效率很低下,所以针对这个子查询执行计划会被优化为,先执行子查询,select x2 from t2 where x3=xxx 这条SQL语句,把查出来的数据写入一个临时表里,也可以叫物化表,意思是把这个中间结果集进行物化,这个物化表会基于memory存储引擎通过内存存放,如果结果集太大,则可能采用普通的b+树聚簇索引的方式放在磁盘里。但无论如何,这个物化表都会建立索引,所以大家清楚,这批中间结果数据写入物化表是有索引的。
接着大家可能会想,此时是不是全表扫描t1表,对每条数据的x1值都去物化表里根据索引快速查找一下是否在这个物化表里?如果是的话,那就符合条件,但是这里还有一个优化的点,那就是可以反过来思考,也就是说,假设t1表有10万条数据,而物化表的数据量只有500条,那么此时完全可以改成全表扫描物化表,对每个数据值到t1表里根据x1这个字段的索引进行查找,查找物化表的这个值是否在t1表的x1索引树里,如果在的话,那么就符合条件。
*物化表和t1表哪个查到的数据少,就以哪个表为驱动表,去被驱动表查询
(3)总结:
所以,基于IN语句的子查询方式,实际上会在底层被优化成如上所述。