Demo Table
代码语言:javascript复制CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
create table t2 like t1;
两个表 t1 和 t2 , 一样的,包括索引信息
数据量 t1 ,t2 如下
代码语言:javascript复制mysql> select count(1) from t1;
----------
| count(1) |
----------
| 10000 |
----------
1 row in set
mysql> select count(1) from t2;
----------
| count(1) |
----------
| 100 |
----------
1 row in set
mysql>
in的逻辑
代码语言:javascript复制select * from t1 where id in (select id from t2) ;
这个SQL,先执行哪个呢?
看看执行计划
可以理解为
代码语言:javascript复制for(select id from t2){
select * from t1 where t1.id = t2.id
}
优化原则
原则:小表驱动大表,即小的数据集驱动大的数据集
当T2表的数据集小于T1表的数据集时,in优于exists
exists的逻辑
代码语言:javascript复制select * from A where exists (select 1 from B where B.id = A.id)
可以理解为
代码语言:javascript复制 for(select * from A){
select * from B where B.id = A.id
}
当A表的数据集小于B表的数据集时,exists优于in
将主查询A的数据,放到子查询B中做条件验证,根据验证结果(true或false)来决定主查询的数据是否保留
- EXISTS (subquery)只返回TRUE或FALSE,因此子查询中的SELECT * 也可以用SELECT 1替换,官方说法是实际执行时会忽略SELECT清单,因此没有区别
- EXISTS子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比
- EXISTS子查询往往也可以用JOIN来代替,何种最优需要具体问题具体分析
mysql> explain select * from t2 where exists (select 1 from t1 where t1.id = t2.id) ;
---- -------------------- ------- ------------ -------- --------------- --------- --------- --------------- ------ ---------- -------------
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
---- -------------------- ------- ------------ -------- --------------- --------- --------- --------------- ------ ---------- -------------
| 1 | PRIMARY | t2 | NULL | ALL | NULL | NULL | NULL | NULL | 100 | 100 | Using where |
| 2 | DEPENDENT SUBQUERY | t1 | NULL | eq_ref | PRIMARY | PRIMARY | 4 | artisan.t2.id | 1 | 100 | Using index |
---- -------------------- ------- ------------ -------- --------------- --------- --------- --------------- ------ ---------- -------------
2 rows in set