首页 > 数据库 >MySQL到底是 join 性能好,还是in一下更快呢?

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

时间:2023-11-09 10:22:58浏览次数:38  
标签:join order user MySQL mysqli NULL id 更快

事情是这样的,去年入职的新公司,之后在代码review的时候被提出说,不要写join,join耗性能还是慢来着,当时也是真的没有多想,那就写in好了,最近发现in的数据量过大的时候会导致sql慢,甚至sql太长,直接报错了。这次来浅究一下,到底是in好还是join好,仅目前认知探寻,有不对之处欢迎指正

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

一、表结构

1、用户表

image

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

image

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

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

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

插播一条:如果你近期准备面试跳槽,建议在ddkk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

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

下面从三个维度来看

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

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;

image

2、分开查

select id,price,user_id from order;
image

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

如此看来,分开查和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();

image

插播一条:如果你近期准备面试跳槽,建议在ddkk.com在线刷题,涵盖 一万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题,还有市面上最全的技术五百套,精品系列教程,免费提供。

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

image

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

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

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

1、join

image

2、分开

image

user
image

3、代码层面

in
image

join
image

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

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

1、join

image

2、分开

order
image
user

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

3、代码层面

in
image

join

image

四、到底怎么才能更好

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

总的来说,当数据量小时,可能一页数据就够放的时候,join的成本和速度都更好。数据量大的时候确实分开查的成本更低,但是由于数据量大,造成循环的成本更多,代码执行的时间也就越长。实验过程中发现,当in的数据量过大的时候,sql过长会无法执行,可能还要拆开多条sql进行查询,这样的查询成本和时间一定也会更长,而且如果有分页的需求的话,也无法满足。。。

总结:

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

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

来源:公众号-架构师专栏

标签:join,order,user,MySQL,mysqli,NULL,id,更快
From: https://www.cnblogs.com/hefeng2014/p/17819097.html

相关文章

  • 记录一次报错,程序启动,MySql自动关闭
    关于初级程序员,对于安装mysql,以及配置可能会报几次错有时候虽然进行第二次安装成功,但是第一次的残留文件还在,可能引起报错在这里记录一次我的报错程序启动导致Mysql自动断开,需要手动打开1、打开任务管理器,打开详细信息,发现界面有两个mysqld.exe如果你是使用单程序连接,或者你......
  • 爬虫-mysql-工具
    MySQL数据库一、MySQL数据库的介绍1、发展史1996年,MySQL1.02008年1月16号Sun公司收购MySQL。2009年4月20,Oracle收购Sun公司。MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),使用最常用的数据库管理语言--结构化查询语言(SQL)进行数据库管理。MySQL是开放源代码的,因此任......
  • Mysql的SQL优化
    1.插入数据环境准备,创建表tb_testcreatetabletb_test(idintnotnullcomment'主键'primarykey,namevarchar(20)nullcomment'姓名',gendercharnullcomment'性别默认1表示男')comment'测试';1.1.inser......
  • Python 数据库应用教程:安装 MySQL 及使用 MySQL Connector
    Python可以用于数据库应用程序。其中最流行的数据库之一是MySQL。MySQL数据库为了能够在本教程中尝试代码示例,您应该在计算机上安装MySQL。您可以在MySQL官方网站下载MySQL数据库。安装MySQL驱动程序Python需要一个MySQL驱动程序来访问MySQL数据库。在本教程中,我们将使用"......
  • Python 数据库应用教程:安装 MySQL 及使用 MySQL Connector
    Python可以用于数据库应用程序。其中最流行的数据库之一是MySQL。MySQL数据库为了能够在本教程中尝试代码示例,您应该在计算机上安装MySQL。您可以在MySQL官方网站下载MySQL数据库。安装MySQL驱动程序Python需要一个MySQL驱动程序来访问MySQL数据库。在本教程中,我们将使用......
  • openEuler22.03操作系统 Linux内核Kernel 5.10 应该选择哪个版本的mysql安装包下载?
    对于openEuler22.03操作系统和Linux内核Kernel5.10,你应该选择与该操作系统和内核版本兼容的MySQL安装包进行安装。在确定适合的MySQL版本时,你可以考虑以下几点:MySQL官方支持:查看MySQL官方网站中的文档或支持页面,确认其是否支持openEuler22.03操作系统和Kernel5.......
  • 0.Hive+MySQL安装记录
    1.确定安装版本如何通过官网查找hadoop、hbase、hive版本兼容信息2.安装流程大概B站视频3.安装mysql数据库centos安装mysql8check:tar命令配置文件(/etc/下)--/etc/profilemysql环境变量配置mysql:errorwhileloadingsharedlibraries:libncurses.so.6:can......
  • Java登陆第一天——Mysql安装
    MySQL是一种开源、免费的关系型数据库官网https://www.mysql.com/由于是外网国内下载很慢可以使用国内镜像阿里云镜像站:https://mirrors.aliyun.com/mysql/搜狐开源镜像站:http://mirrors.sohu.com/mysql/建议下载压缩包。下载解压文件夹文件夹放在自己想放的目录下配......
  • DataGrip连接MySql数据库失败:dataGrip java.net.ConnectException: Connection refuse
    1.问题报错:dataGripjava.net.ConnectException:Connectionrefused:connect.详细错误:[08S01]CommunicationslinkfailureThelastpacketsentsuccessfullytotheserverwas0millisecondsago.Thedriverhasnotreceivedanypacketsfromtheserver.Communica......
  • MySql按周,按月,按日分组统计数据
    知识关键词:DATE_FORMAT<!--按日查询-->SELECTDATE_FORMAT(created_date,'%Y-%m-%d')astime,sum(money)moneyFROMo_finance_detailwhereorg_id=1000GROUPBYtime<!--按月查询-->SELECTDATE_FORMAT(created_date,'%Y-%m')astime,su......