MySQL in exists

269 阅读2分钟

目标:分析MySQL in exists的内部机制

分析:

in exists.png

详解:

第一部分 in exists内部机制

直接先看一个对比

小表,里面有10条数据
CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

大表,里面有2598750条数据
CREATE TABLE `orders` (
  `id` int NOT NULL AUTO_INCREMENT,
  `order_no` varchar(20) NOT NULL,
  `title` varchar(20) NOT NULL,
  `goods_num` int NOT NULL,
  `money` decimal(7,4) NOT NULL,
  `user_id` int NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2598751 DEFAULT CHARSET=utf8mb3;

in 外部大表,子查询小表
in 外部大表,子查询小表
explain select count(1) from orders o where o.user_id in (select u.id from users u);
show warnings;

MySQL解析
/* select#1 */ select count(1) AS `count(1)` from `testdb6`.`users` `u` join `testdb6`.`orders` `o` where (`testdb6`.`o`.`user_id` = `testdb6`.`u`.`id`)
exists 外部大表,子查询小表
exists 外部大表,子查询小表
explain select count(1) from orders o where exists (select 1 from users u where u.id = o.user_id);
show warnings;

MySQL解析
/* select#1 */ select count(1) AS `count(1)` from `testdb6`.`users` `u` join `testdb6`.`orders` `o` where (`testdb6`.`o`.`user_id` = `testdb6`.`u`.`id`)
in 外部小表,子查询大表
in 外部小表,子查询大表
explain select count(1) from users u where u.id in (select o.user_id from orders o);
show warnings;

MySQL解析
/* select#1 */ select count(1) AS `count(1)` from `testdb6`.`users` `u` semi join (`testdb6`.`orders` `o`) where (`testdb6`.`o`.`user_id` = `testdb6`.`u`.`id`)
exists 外部小表,子查询大表
exists 外部小表,子查询大表
explain select count(1) from users u where exists (select 1 from orders o where o.user_id = u.id);
show warnings;

MySQL解析
/* select#1 */ select count(1) AS `count(1)` from `testdb6`.`users` `u` semi join (`testdb6`.`orders` `o`) where (`testdb6`.`o`.`user_id` = `testdb6`.`u`.`id`)

关于semi join的说明,请查看这篇文章,www.linuxidc.com/Linux/2015-… 写的非常好。

第二部分 in exists误区

  • in 是先执行子查询,适合于外表大而内表小的情况。
  • exists 是以外层表为驱动表,先被访问,适合于外表小而内表大的情况。 这两句话熟悉吗,经常在MySQL优化的文章中看到,从上边的对比我们看到,其实in跟exists的执行优化是一样的。我测试使用的是MySQL8.0.25,如果MySQL的版本比较低的话,可以自己测试一下,MySQL随着版本迭代也做了很多优化。所以没有万能的方法,很多都需要自己测试。

第三部分 参考