一直聽說exists性能比in快,但為啥快,一直不明白,乘着今天重點研究mysql,看到底是不是這么回事,原因又是在哪里。
1、我們先准備2張表和數據,人員表插入100W條數據,部門表插入5條數據。
DROP TABLE IF EXISTS `bd_dept`; CREATE TABLE `bd_dept` ( `id` int(0) NOT NULL, `dept_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '部門名稱',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '部門' ROW_FORMAT = Dynamic; DROP TABLE IF EXISTS `bd_user`; CREATE TABLE `bd_user` ( `id` bigint(0) NOT NULL, `dept_id` int(0) NULL DEFAULT NULL COMMENT '部門ID', `user_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用戶名稱',PRIMARY KEY (`id`) USING BTREE,INDEX `dept_id`(`dept_id`) USING BTREE, CONSTRAINT `bd_user_ibfk_1` FOREIGN KEY (`dept_id`) REFERENCES `bd_dept` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '人員' ROW_FORMAT = DYNAMIC;
2、我們測試一下結果
1)根據部門名稱找所有該部門下的人員信息:
select * from bd_user a where exists (select 1 from bd_dept b where b.dept_name='研發中心' and b.id=a.dept_id) > OK > Time: 0.814s select * from bd_user a where a.dept_id in (select id from bd_dept b where b.dept_name='研發中心') > OK > Time: 0.8s
從結果上看,in和exists查詢效率基本一致,多次執行執行查詢,看不出來誰快誰慢。我們看下他們的執行計划:
mysql> explain select * from bd_user a where exists (select 1 from bd_dept b where b.dept_name='研發中心' and b.id=a.dept_id); +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+ | 1 | SIMPLE | b | NULL | ALL | PRIMARY | NULL | NULL | NULL | 4 | 25.00 | Using where | | 1 | SIMPLE | a | NULL | ref | dept_id | dept_id | 5 | zhi_test.b.id | 332010 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+
mysql> explain select * from bd_user a where a.dept_id in (select id from bd_dept b where b.dept_name='研發中心'); +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+ | 1 | SIMPLE | b | NULL | ALL | PRIMARY | NULL | NULL | NULL | 4 | 25.00 | Using where | | 1 | SIMPLE | a | NULL | ref | dept_id | dept_id | 5 | zhi_test.b.id | 332010 | 100.00 | NULL | +----+-------------+-------+------------+------+---------------+---------+---------+---------------+--------+----------+-------------+
他們的執行計划完全相同。
2)根據人員名稱找他所在部門的信息:
select * from bd_dept a where exists (select 1 from bd_user b where b.user_name='測試0000000031' and a.id=b.dept_id) > OK > Time: 0.19s select * from bd_dept a where a.id in (select b.dept_id from bd_user b where b.user_name='測試0000000031') > OK > Time: 0.19s
從結果上看in和exists效率還是一樣的,我們再看看執行計划
mysql> explain select * from bd_dept a where exists (select 1 from bd_user b where b.user_name='測試0000000031' and a.id=b.dept_id); +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+ | 1 | SIMPLE | a | NULL | ALL | PRIMARY | NULL | NULL | NULL | 4 | 100.00 | Using where | | 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_distinct_key> | <auto_distinct_key> | 5 | zhi_test.a.id | 1 | 100.00 | NULL | | 2 | MATERIALIZED | b | NULL | ALL | dept_id | NULL | NULL | NULL | 996030 | 10.00 | Using where | +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+
mysql> explain select * from bd_dept a where a.id in (select b.dept_id from bd_user b where b.user_name='測試0000000031'); +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+ | 1 | SIMPLE | a | NULL | ALL | PRIMARY | NULL | NULL | NULL | 4 | 100.00 | Using where | | 1 | SIMPLE | <subquery2> | NULL | eq_ref | <auto_distinct_key> | <auto_distinct_key> | 5 | zhi_test.a.id | 1 | 100.00 | NULL | | 2 | MATERIALIZED | b | NULL | ALL | dept_id | NULL | NULL | NULL | 996030 | 10.00 | Using where | +----+--------------+-------------+------------+--------+---------------------+---------------------+---------+---------------+--------+----------+-------------+
這2個SQL的執行計划也完全相同。
3、結論
實踐出真知,in和exists的性能在MySQL8.x中是一樣的。
