mysql - 为什么带有 'exists' 的 sql 运行速度比使用 MySQL 的 'in' 慢

标签 mysql sql optimization exists where-in

我是 MySQL 优化的新手,我发现了一个惊人的事情:带有 'exists' 的 sql 运行速度比使用 'in' 慢!!!

以下是我的 DDL:

mysql> `show create table order\G`;
*************************** 1. row ***************************
       Table: order
Create Table: CREATE TABLE `order` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `employee_id` int(4) NOT NULL,
  `price` decimal(7,2) NOT NULL,
  `trade_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `fk_employee_id` (`employee_id`),
  CONSTRAINT `fk_employee_id` FOREIGN KEY (`employee_id`) REFERENCES `employee` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=231001 DEFAULT CHARSET=utf8



mysql> `show create table order_detail\G`;
*************************** 1. row ***************************
       Table: order_detail
Create Table: CREATE TABLE `order_detail` (
  `id` int(4) NOT NULL AUTO_INCREMENT,
  `menu_id` int(4) NOT NULL,
  `order_id` int(4) NOT NULL,
  `amount` int(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `fk_menu_id` (`menu_id`),
  KEY `fk_order_id` (`order_id`),
  CONSTRAINT `fk_menu_id` FOREIGN KEY (`menu_id`) REFERENCES `menu` (`id`),
  CONSTRAINT `fk_order_id` FOREIGN KEY (`order_id`) REFERENCES `order` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1037992 DEFAULT CHARSET=utf8



Query Solution 1: use exists
---------------------------------

mysql> `SELECT count(`order`.id) FROM `order` WHERE EXISTS ( SELECT 1 FROM order_detail WHERE order_detail.order_id = `order`.id GROUP BY (order_detail.order_id) HAVING COUNT(order_id) > 5 );`
+-------------------+
| count(`order`.id) |
+-------------------+
|             92054 |
+-------------------+
1 row in set (***6.53 sec***)

mysql> `explain SELECT count(`order`.id) FROM `order` WHERE EXISTS ( SELECT 1 FROM order_detail WHERE order_detail.order_id = `order`.id GROUP BY (order_detail.order_id) HAVING COUNT(order_id) > 5 )\G;`
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: order
         type: index
possible_keys: NULL
          key: fk_employee_id
      key_len: 4
          ref: NULL
         rows: 231032
        Extra: Using where; Using index
*************************** 2. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: order_detail
         type: ref
possible_keys: fk_order_id
          key: fk_order_id
      key_len: 4
          ref: performance_test.order.id
         rows: 3
        Extra: Using where; Using index
2 rows in set (0.01 sec)


Query solution 2: use in
------------------------

mysql> `SELECT count(`order`.id) FROM `order` WHERE `order`.id IN ( SELECT order_detail.order_id FROM order_detail GROUP BY (order_detail.order_id) HAVING COUNT(order_id) > 5 ) ;`
+-------------------+
| count(`order`.id) |
+-------------------+
|             92054 |
+-------------------+
1 row in set (***3.88 sec***)

mysql> `explain SELECT count(`order`.id) FROM `order` WHERE `order`.id IN ( SELECT order_detail.order_id FROM order_detail GROUP BY (order_detail.order_id) HAVING COUNT(order_id) > 5 ) \G;`<br>
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: order
         type: index
possible_keys: NULL
          key: fk_employee_id
      key_len: 4
          ref: NULL
         rows: 231032
        Extra: Using where; Using index
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY
        table: order_detail
         type: index
possible_keys: fk_order_id
          key: fk_order_id
      key_len: 4
          ref: NULL
         rows: 1036314
        Extra: Using index
2 rows in set (0.00 sec)

最佳答案

我觉得你有点困惑,你有一个错误的想法,'EXISTS' 比 'IN' 工作得更快,我试图让你理解原因..

EXISTS 返回一个 bool 值,并将在第一次匹配时返回一个 bool 值。因此,如果您要处理重复项/多个项,根据数据和需求,“EXISTS”的执行速度将比“IN”或“JOIN”快。

而“IN”是 OR 子句的语法糖。虽然它非常方便,但在处理该比较的大量值(超过 1,000)时存在问题。在重复/倍数的情况下,“IN”会检查所有存在的值,这自然会比“EXISTS”消耗更多的执行时间,这就是为什么“IN”总是比“EXISTS”慢。

我希望我澄清了你的困惑。

关于mysql - 为什么带有 'exists' 的 sql 运行速度比使用 MySQL 的 'in' 慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20172487/

相关文章:

python - 是什么导致 symfit 出现此警告?

mysql - 为MySQL存储过程中的所有表设置默认排序规则

php - 如何使用php将数据插入到包含外键的表中?

mysql - 将我的表中已删除的数据恢复到原始状态

php - SQL:不存在的地方 - 仅在不存在时插入

mysql - 如何在SQL中获取特定记录列的最小值?

mysql - 如何在MySQL查询中更好地获取不同的行?

python - 如何将数据集拆分/分区为训练和测试数据集,例如交叉验证?

java - 将包含百万值的 csv 文件上传到 mysql 中的特定列

optimization - 在 Rust 中空函数会被优化掉吗?