日常开发中,使用in和exists子查询是非常常见的,那么他们之前有什么区别,该如何选择是能达到最佳查询效果呢?
假设现在有两个表:用户表(t_user)、订单表(t_order)
| 用户表 | 字段 |
|---|---|
| id | 主键ID |
| username | 用户名 |
| age | 年龄 |
| address | 地址 |
用户表存在4条数据:
| 订单表 | 字段 |
|---|---|
| id | 主键ID |
| order_no | 订单编号 |
| user_id | 用户id |
| amount | 订单金额 |
订单表存在两条数据:
先看两个子查询sql:
in查询
SELECT * FROM t_user WHERE id in (SELECT user_id FROM t_order)
exists查询
上面的sql语句相当于
SELECT * FROM t_user WHERE EXISTS (SELECT * FROM t_order WHERE t_order.user_id = t_user.id)
实际上区分in和exists主要是考虑驱动顺序的改变(这也是性能变化的关键),如果是exists,那么是一外层为驱动表,先被驱动,如果是in,那么先执行子查询,所以in适合于外表大而内表子查询小的情况,exists适合于外表小而内表子查询大的情况。
关于not in和not exists,推荐使用not exists!可以采用join的方式高效替代not exists的sql语句,比如:
查询没有下过单的用户,原sql语句:
SELECT * FROM t_user WHERE id not in (SELECT user_id FROM t_order);
采用join的方式替换:
SELECT u.*, o.user_id FROM t_user u LEFT JOIN t_order o ON u.id = o.user_id WHERE o.user_id is null
查询结果都是:
现在我往订单表批量插入数据,用户表数据条数还是4,订单表目前存在数据是419万,观察in和exists查询sql性能问题:
经过实际查询验证采用join方式替代not exists有助于性能提升,同样的需求:查询没有下过单的用户,执行:
SELECT * FROM t_user WHERE id not in (SELECT user_id FROM t_order);
5次的用时分别是:1.263s、1.279s、1.269s、1.267s、1.268s,每次not in方式查询大约是1.26s左右。
SELECT u.*, o.user_id FROM t_user u LEFT JOIN t_order o ON u.id = o.user_id WHERE o.user_id is null;
5次的用时分别是:0.741s、0.744s、0.746s、0.747s、0.801s,每次left join方式查询大约是0.75s左右。
证实了:可以采用join的方式高效替代not in/not exists的sql语句这个结论!!