首页 > 数据库 >面试官:MySQL 到底是 join 性能好,还是 in 一下更快呢?被问懵逼了…

面试官:MySQL 到底是 join 性能好,还是 in 一下更快呢?被问懵逼了…

时间:2023-12-27 14:55:52浏览次数:36  
标签:面试官 join id user MySQL mysqli NULL order

来源:https://juejin.cn/post/7169567387527282701

先总结:

  1. 数据量小的时候,用join更划算
  2. 数据量大的时候,join的成本更高,但相对来说join的速度会更快
  3. 数据量过大的时候,in的数据量过多,会有无法执行SQL的问题,待解决

事情是这样的,去年入职的新公司,之后在代码review的时候被提出说,不要写join,join耗性能还是慢来着,当时也是真的没有多想,那就写in好了,最近发现in的数据量过大的时候会导致sql慢,甚至sql太长,直接报错了。

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

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

一、表结构

1、用户表

 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、订单表

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

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

二、先来试少量数据的情况

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

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

下面从三个维度来看

多表连接查询成本 = 一次驱动表成本 + 从驱动表查出的记录数 * 一次被驱动表的成本

1、join

JOIN:

explain format=json select order.id, price, user.`name` from `order` join user on order.user_id = user.id;

子查询:

select order.id,price,user.`name` from `order`,user where user_id=user.id;

2、分开查

select `id`,price,user_id from `order`;

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\]

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

3、代码层面

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

ab -n 100 -c 10

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();

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();

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

三、试下多一些数据的情况

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

1、join

2、分开

order

user

3、代码层面

in

join

三、试下多一些数据的情况

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

1、join

2、分开

order

user

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

3、代码层面

in

join

四、到底怎么才能更好

注:对于本机来说100000条数据不少了,更大的数据量害怕电脑卡死

总的来说,当数据量小时,可能一页数据就够放的时候,join的成本和速度都更好。数据量大的时候确实分开查的成本更低,但是由于数据量大,造成循环的成本更多,代码执行的时间也就越长。

实验过程中发现,当in的数据量过大的时候,sql过长会无法执行,可能还要拆开多条sql进行查询,这样的查询成本和时间一定也会更长,而且如果有分页的需求的话,也无法满足。。。

感觉这两个方法都不是太好,各位小伙伴,有没有更好的方法呢?

参考资料:

https://www.cnblogs.com/zhuwenjoyce/p/14968183.html

https://blog.csdn.net/xjk201/article/details/122051216

https://juejin.cn/book/6844733769996304392/section/6844733770055024647

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

标签:面试官,join,id,user,MySQL,mysqli,NULL,order
From: https://www.cnblogs.com/javastack/p/17930562.html

相关文章

  • 12-Mysql的日志管理
    一、mysql常见日志二、错误日志配置方法:[mysqld]log-error=/data/mysql/mysql.log查看配置方式:mysql>showvariableslike'%log%error%';作用:记录mysql数据库的一般状态信息及报错信息,是我们对于数据库常规报错处理的常用日志,默认在data目录下三、一般查询......
  • 14-Mysql主从复制
    一、mysql复制原理1.1主从复制原理过程从库的I/Othread线程会读取masterinfo文件获取主库的user,passwordport信息然后还会获取上次获取主库二进制日志的位置如3640就是00003这个文件640这个位置,主库收到从库的请求后,会验证用户名密码等的合法性,然后问主库你有没有......
  • 04-Mysql多实例
    多实例就是多套线程和多各进程和多个预分配的内存结构配置思路启动多个mysqld进程规划多套数据规划多个端口规划多套日志路径配置例子1、创建多套目录mkdir-p/data/330{7,8,9}2、准备多套配置文件vi/data/3307/my.cnf[mysqld]basedir=/application/mysqldatadi......
  • 05-Mysql 用户管理
    一、MySQL用户管理用户定义:user主机范围使用某个用户从哪个(些)地址访问我的数据库用户的功能:1、用来登录mysql数据库2、用来管理数据库对象(库、表)权限功能:针对不同用户设置对不同对象管理能力selectupdatedeleteinsertcreatedrop。。。权限范围:......
  • 01-Mysql介绍及安装
    关系型数据库的特点二维表典型产品Oracle传统企业,MySQL是互联网企业数据存取是通过SQL最大特点,数据安全性方面强(ACID)•NoSQL:非关系型数据库(NotonlySQL)不是否定关系型数据库,做关系型数据库的的补充想做老大,先学会做老二•NoSQL特性总览–不是否定......
  • 在windows下安装mysql 8.1
    1、下载并解压官网下载mysql8,https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.11-winx64.zip解压到D:\mysql,以下称为根目录2、编写配置文件在根目录下新建my.ini文件,配置以下内容[mysqld]#设置3306端口port=3306#设置mysql的安装目录,一定要与上面的安装路......
  • 02-Mysql体系结构
    一、MySQL服务器连接模型2、应用程序如何连接到mysql2.1tcp/ip的方式mysql-uroot-poldboy123-h10.0.0.2002.2套接字的方式mysql-uroot-poldboy123-S/tmp/mysql.sock二、MySQL服务器构成——实例连接层sql层处理流程解析器(执行计划)--优化器(选择比......
  • 03-MySQL基本管理
    一、数据库连接管理mysql-uroot-poldboy123#隐藏条件-S默认socket方式mysql-uroot-poldboy123-h10.0.0.52-P3308#tcp/ip的方式mysql-uroot-poldboy123-S/application/mysql/tmp/mysql.sock#socket方式mysql-uroot-poldboy123-e"showvariableslike......
  • Mysql根据字段值的长度查找过滤,排序等
    Mysql根据字段值的长度查找过滤,排序等http://www.shanhubei.com/archives/5882.html1.Mysql根据字段的指定长度搜索过滤SELECT*FROMuserWHEREis_deleted=0ANDlength(name)>52.添加普通索引ALTERTABLE'table_name'ADDINDEXindex_name('column')3.在表中某一列......
  • Windows 平台下如何安装与配置 MySQL 5.7.36
    Windows一般使用两种MySQL安装方式,即MySQL二进制分发版(.msi安装文件)和免安装版(.zip压缩文件)。一般来讲,应当使用二进制分发版,因为该版本比其他的分发版使用起来要简单,不再需要其他工具来启动就可以运行MySQL。本次实验是在Windows10平台上选用图形化的二进制安装方式,其他W......