服务器之家:专注于服务器技术及软件下载分享
分类导航

Mysql|Sql Server|Oracle|Redis|MongoDB|PostgreSQL|Sqlite|DB2|mariadb|Access|数据库技术|

服务器之家 - 数据库 - Mysql - MySQL到底是join性能好,还是in一下更快呢?

MySQL到底是join性能好,还是in一下更快呢?

2023-11-17 01:00未知服务器之家 Mysql

大家好呀,我是楼仔。 今天发现一篇很有意思的文章,使用 mysql 查询时,是使用 join 好,还是直接 in 更好,这个大家工作时经常遇到。 为了方便大家查看,文章我重新进行了排版。 我没有直接用作者的结论,感觉可能会误导读

大家好呀,我是楼仔。

今天发现一篇很有意思的文章,使用 mysql 查询时,是使用 join 好,还是直接 in 更好,这个大家工作时经常遇到。

为了方便大家查看,文章我重新进行了排版。

我没有直接用作者的结论,感觉可能会误导读者,而是根据实验结果,给出我自己的建议。

不 BB,上目录:

MySQL到底是join性能好,还是in一下更快呢?图片

01 背景

事情是这样的,去年入职的新公司,之后在代码 review 的时候被提出说,不要写 join,join 耗性能还是慢来着,当时也是真的没有多想,那就写 in 好了。

最近发现 in 的数据量过大的时候会导致 sql 慢,甚至 sql 太长,直接报错了。

这次来浅究一下,到底是 in 好还是 join 好,仅目前认知探寻,有不对之处欢迎指正。

以下实验仅在本机电脑试验。

02 表结构

2.1 用户表

MySQL到底是join性能好,还是in一下更快呢?图片

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '姓名',
  `gender` smallint DEFAULT NULL COMMENT '性别',
  `mobile` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`),
  UNIQUE KEY `mobile` (`mobile`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1005 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

2.2 订单表

MySQL到底是join性能好,还是in一下更快呢?图片

CREATE TABLE `order` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `price` decimal(18,2) NOT NULL,
  `user_id` int NOT NULL,
  `product_id` int NOT NULL,
  `status` smallint NOT NULL DEFAULT '0' COMMENT '订单状态',
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  KEY `product_id` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

03 千条数据情况

数据量:用户表插一千条随机生成的数据,订单表插一百条随机数据

要求:查下所有的订单以及订单对应的用户

耗时衡量指标:多表连接查询成本 = 一次驱动表成本 + 从驱动表查出的记录数 * 一次被驱动表的成本

3.1 join

select order.id, price, user.name from order join user on order.user_id = user.id;

MySQL到底是join性能好,还是in一下更快呢?图片

3.2 in

select id,price,user_id from order;

MySQL到底是join性能好,还是in一下更快呢?图片

select name from user where id in (8, 11, 20, 32, 49, 58, 64, 67, 97, 105, 113, 118, 129, 173, 179, 181, 210, 213, 215, 216, 224, 243, 244, 251, 280, 309, 319, 321, 336, 342, 344, 349, 353, 358, 363, 367, 374, 377, 380, 417, 418, 420, 435, 447, 449, 452, 454, 459, 461, 472, 480, 487, 498, 499, 515, 525, 525, 531, 564, 566, 580, 584, 586, 592, 595, 610, 633, 635, 640, 652, 658, 668, 674, 685, 687, 701, 718, 720, 733, 739, 745, 751, 758, 770, 771, 780, 806, 834, 841, 856, 856, 857, 858, 882, 934, 942, 983, 989, 994, 995);

其中 in 的是order查出来的所有用户 id。

MySQL到底是join性能好,还是in一下更快呢?图片

如此看来,分开查和 join 查的成本并没有相差许多。

3.3 并发场景

主要用php原生写了脚本,用ab进行10个同时的请求,看下时间,进行比较。

> ab -n 100 -c 10 // 执行脚本

下面是 join 查询的执行脚本:

$mysqli = new mysqli('127.0.0.1', 'root', 'root', 'test');
if ($mysqli->connect_error) {
    die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}

$result = $mysqli->query('select order.id, price, user.`name` from `order` join user on order.user_id = user.id;');
$orders = $result->fetch_all(MYSQLI_ASSOC);

var_dump($orders);
$mysqli->close();

MySQL到底是join性能好,还是in一下更快呢?图片

下面是 in 查询的执行脚本:

$mysqli = new mysqli('127.0.0.1', 'root', 'root', 'test');
 if ($mysqli->connect_error) {
     die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
 }

 $result = $mysqli->query('select `id`,price,user_id from `order`');
 $orders = $result->fetch_all(MYSQLI_ASSOC);

 $userIds = implode(',', array_column($orders, 'user_id')); // 获取订单中的用户id
 $result = $mysqli->query("select `id`,`name` from `user` where id in ({$userIds})");
 $users = $result->fetch_all(MYSQLI_ASSOC);// 获取这些用户的姓名

 // 将id做数组键
 $userRes = [];
 foreach ($users as $user) {
     $userRes[$user['id']] = $user['name'];
 }

 $res = [];
 // 整合数据
 foreach ($orders as $order) {
     $current = [];
     $current['id'] = $order['id'];
     $current['price'] = $order['price'];
     $current['name'] = $userRes[$order['user_id']] ?: '';
     $res[] = $current;
 }
 var_dump($res);

 // 关闭mysql连接

 $mysqli->close();

MySQL到底是join性能好,还是in一下更快呢?图片

看时间的话,明显 join 更快一些。

04 万条数据情况

user表现在10000条数据,order表10000条试下。

4.1 join

MySQL到底是join性能好,还是in一下更快呢?图片

4.2 in

order 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

user 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

4.3 并发场景

join 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

in 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

数据量达到万级别,非并发场景,in 更快,并发场景 join 更快。

05 十万条数据情况

随机插入后user表十万条数据,order表一百万条试下。

5.1 join

MySQL到底是join性能好,还是in一下更快呢?图片

5.2 in

order 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

user 耗时:

order查出来的结果过长了...

5.3 并发场景

join 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

in 耗时:

MySQL到底是join性能好,还是in一下更快呢?图片

数据量达到十万/百万级别,非并发场景,in 过长,并发场景 join 更快。

06 总结

实验结论:

  • 数据量不到万级别,join 和 in 差不多;
  • 数据量达到万级别,非并发场景,in 更快,并发场景 join 更快;
  • 数据量达到十万/百万级别,非并发场景,in 过长,并发场景 join 更快。

下面是楼仔给出的一些建议。

当数据量比较小时,建议用 in,虽然两者的性能差不多,但是 join 会增加 sql 的复杂度,后续再变更,会非常麻烦。

当数据量比较大时,建议用 join,主要还是出于查询性能的考虑。

不过使用 join 时,小表驱动大表,一定要建立索引,join 的表最好不要超过 3 个,否则性能会非常差,还会大大增加 sql 的复杂度,非常不利于后续功能扩展。

延伸 · 阅读

精彩推荐
  • MysqlMySQL数据库varchar的限制规则说明

    MySQL数据库varchar的限制规则说明

    本文我们主要介绍了MySQL数据库中varchar的限制规则,并以一个实际的例子对限制规则进行了说明,希望能够对您有所帮助。 ...

    mysql技术网4192019-11-23
  • MysqlERROR: Error in Log_event::read_log_event()

    ERROR: Error in Log_event::read_log_event()

    ERROR: Error in Log_event::read_log_event(): read error, data_len: 438, event_type: 2 ...

    MYSQL教程网6412020-03-13
  • Mysql详解MySQL中的分组查询与连接查询语句

    详解MySQL中的分组查询与连接查询语句

    这篇文章主要介绍了MySQL中的分组查询与连接查询语句,同时还介绍了一些统计函数的用法,需要的朋友可以参考下 ...

    GALAXY_ZMY5442020-06-03
  • Mysql浅谈mysql 树形结构表设计与优化

    浅谈mysql 树形结构表设计与优化

    在诸多的管理类,办公类等系统中,树形结构展示随处可见,本文主要介绍了mysql 树形结构表设计与优化,具有一定的参考价值,感兴趣的小伙伴们可以参...

    小码农叔叔5242021-11-16
  • MysqlMySQL锁的知识点总结

    MySQL锁的知识点总结

    在本篇文章里小编给大家整理了关于MySQL锁的知识点总结以及实例内容,需要的朋友们学习下。...

    别人放弃我坚持吖4362020-12-14
  • Mysql解决MySQl查询不区分大小写的方法讲解

    解决MySQl查询不区分大小写的方法讲解

    今天小编就为大家分享一篇关于解决MySQl查询不区分大小写的方法讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起...

    Veir_dev5592019-06-25
  • MysqlMySQL 数据备份与还原的示例代码

    MySQL 数据备份与还原的示例代码

    这篇文章主要介绍了MySQL 数据备份与还原的相关知识,本文通过示例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...

    逆心2972019-06-23
  • Mysqlmysql 不能插入中文问题

    mysql 不能插入中文问题

    当向mysql5.5插入中文时,会出现类似错误 ERROR 1366 (HY000): Incorrect string value: '\xD6\xD0\xCE\xC4' for column ...

    MYSQL教程网5722019-11-25