阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

MySQL多表联合查询语句的编写及效率分析、优化

465次阅读
没有评论

共计 8106 个字符,预计需要花费 21 分钟才能阅读完成。

一、多表连接类型


1. 笛卡尔积 (交叉连接)
在 MySQL 中可以为 CROSS JOIN 或者省略 CROSS 即 JOIN,或者使用 ’,’ 如:

SELECT * FROM table1 CROSS JOIN table2   
SELECT * FROM table1 JOIN table2   
SELECT * FROM table1,table2  
SELECT * FROM users CROSS JOIN articles;
SELECT * FROM users JOIN articles;
SELECT * FROM users, articles;

由于其返回的结果为被连接的两个数据表的乘积,因此当有 WHERE, ON 或 USING 条件的时候一般不建议使用,因为当数据表项目太多的时候,会非常慢。一般使用 LEFT [OUTER] JOIN 或者 RIGHT [OUTER] JOIN

2. 内连接 INNER JOIN
在 MySQL 中把 INNER JOIN 叫做等值连接,即需要指定等值连接条件在 MySQL 中 CROSS 和 INNER JOIN 被划分在一起。

SELECT * FROM users as u INNER JOIN articles as a where u.id = a.user_id 

3. MySQL 中的外连接
分为左外连接和右连接,即除了返回符合连接条件的结果之外,还要返回左表 (左连接) 或者右表 (右连接) 中不符合连接条件的结果,相对应的使用 NULL 对应。

例子:
users 表:

+----+----------+----------+--------------------+
| id | username | password | email              |
+----+----------+----------+--------------------+
|  1 | junxi    | 123      | xinlei3166@126.com |
|  2 | tangtang | 456      | xinlei3166@126.com |
|  3 | ceshi3   | 456      | ceshi3@11.com      |
|  4 | ceshi4   | 456      | ceshi4@qq.com      |
|  5 | ceshi3   | 456      | ceshi3@11.com      |
|  6 | ceshi4   | 456      | ceshi4@qq.com      |
|  7 | ceshi3   | 456      | ceshi3@11.com      |
|  8 | ceshi4   | 456      | ceshi4@qq.com      |
|  9 | ceshi3   | 333      | ceshi3@11.com      |
| 10 | ceshi4   | 444      | ceshi4@qq.com      |
| 11 | ceshi3   | 333      | ceshi3@11.com      |
| 12 | ceshi4   | 444      | ceshi4@qq.com      |
+----+----------+----------+--------------------+

userinfos 表:

+----+-------+--------+-------------+----------------+---------+
| id | name  | qq     | phone       | link           | user_id |
+----+-------+--------+-------------+----------------+---------+
|  1 | 君惜  | 666666 | 16616555188 | www.junxi.site |       1 |
|  2 | 糖糖  | 777777 | 17717555177 | www.weizhi.com |       2 |
|  3 | 测试 3 | 333333 | 13313333177 | www.ceshi3.com |       3 |
+----+-------+--------+-------------+----------------+---------+

SQL 语句:

SELECT * FROM users as u LEFT JOIN userinfos as i on u.id = i.user_id;

执行结果:

+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+
| id | username | password | email              | id   | name  | qq     | phone       | link           | user_id |
+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+
|  1 | junxi    | 123      | xinlei3166@126.com |    1 | 君惜  | 666666 | 16616555188 | www.junxi.site |       1 |
|  2 | tangtang | 456      | xinlei3166@126.com |    2 | 糖糖  | 777777 | 17717555177 | www.weizhi.com |       2 |
|  3 | ceshi3   | 456      | ceshi3@11.com      |    3 | 测试 3 | 333333 | 13313333177 | www.ceshi3.com |       3 |
|  4 | ceshi4   | 456      | ceshi4@qq.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
|  5 | ceshi3   | 456      | ceshi3@11.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
|  6 | ceshi4   | 456      | ceshi4@qq.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
|  7 | ceshi3   | 456      | ceshi3@11.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
|  8 | ceshi4   | 456      | ceshi4@qq.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
|  9 | ceshi3   | 333      | ceshi3@11.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
| 10 | ceshi4   | 444      | ceshi4@qq.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
| 11 | ceshi3   | 333      | ceshi3@11.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
| 12 | ceshi4   | 444      | ceshi4@qq.com      | NULL | NULL  | NULL   | NULL        | NULL           |    NULL |
+----+----------+----------+--------------------+------+-------+--------+-------------+----------------+---------+

分析:
而 users 表中的 id 大于 3 的用户在 userinfos 中没有相应的纪录,但是却出现在了结果集中
因为现在是 left join,所有的工作以 left 为准.
结果 1,2,3 都是既在左表又在右表的纪录 4, 5, 6, 7, 8, 9, 10, 11, 12 是只在左表,不在右表的纪录

工作原理:
从左表读出一条,选出所有与 on 匹配的右表纪录 (n 条) 进行连接,形成 n 条纪录 (包括重复的行),如果右边没有与 on 条件匹配的表,那连接的字段都是 null. 然后继续读下一条。
引申:
我们可以用右表没有 on 匹配则显示 null 的规律, 来找出所有在左表,不在右表的纪录,注意用来判断的那列必须声明为 not null 的。
如:
SQL:
(注意:
1. 列值为 null 应该用 is null 而不能用 =NULL
2. 这里 i.user_id 列必须声明为 NOT NULL 的.

SELECT * FROM users as u LEFT JOIN userinfos as i on u.id = i.user_id WHERE i.user_id is NULL;

执行结果:

+----+----------+----------+---------------+------+------+------+-------+------+---------+
| id | username | password | email         | id   | name | qq   | phone | link | user_id |
+----+----------+----------+---------------+------+------+------+-------+------+---------+
|  4 | ceshi4   | 456      | ceshi4@qq.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
|  5 | ceshi3   | 456      | ceshi3@11.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
|  6 | ceshi4   | 456      | ceshi4@qq.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
|  7 | ceshi3   | 456      | ceshi3@11.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
|  8 | ceshi4   | 456      | ceshi4@qq.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
|  9 | ceshi3   | 333      | ceshi3@11.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
| 10 | ceshi4   | 444      | ceshi4@qq.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
| 11 | ceshi3   | 333      | ceshi3@11.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
| 12 | ceshi4   | 444      | ceshi4@qq.com | NULL | NULL | NULL | NULL  | NULL |    NULL |
+----+----------+----------+---------------+------+------+------+-------+------+---------+

一般用法:
a. LEFT [OUTER] JOIN:
除了返回符合连接条件的结果之外,还需要显示左表中不符合连接条件的数据列,相对应使用 NULL 对应

SELECT column_name FROM table1 LEFT [OUTER] JOIN table2 ON table1.column=table2.column 

b. RIGHT [OUTER] JOIN:
RIGHT 与 LEFT JOIN 相似不同的仅仅是除了显示符合连接条件的结果之外,还需要显示右表中不符合连接条件的数据列,相应使用 NULL 对应

SELECT column_name FROM table1 RIGHT [OUTER] JOIN table2 ON table1.column=table2.column  

Tips:

  1. on a.c1 = b.c1 等同于 using(c1)
  2. INNER JOIN 和 , (逗号) 在语义上是等同的
  3. 当 MySQL 在从一个表中检索信息时,你可以提示它选择了哪一个索引。
    如果 EXPLAIN 显示 MySQL 使用了可能的索引列表中错误的索引,这个特性将是很有用的。
    通过指定 USE INDEX (key_list),你可以告诉 MySQL 使用可能的索引中最合适的一个索引在表中查找记录行。
    可选的二选一句法 IGNORE INDEX (key_list) 可被用于告诉 MySQL 不使用特定的索引。如:
mysql> SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3;  
mysql> SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;  
二、表连接的约束条件

添加显示条件 WHERE, ON, USING

1. WHERE 子句

SELECT * FROM table1,table2 WHERE table1.id=table2.id;  
SELECT * FROM users, userinfos WHERE users.id=userinfos.user_id;

2. ON

SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id;  
SELECT * FROM table1 LEFT JOIN table2 ON table1.id=table2.id LEFT JOIN table3 ON table2.id=table3.id;  
SELECT * FROM users LEFT JOIN articles ON users.id = articles.user_id;
SELECT * FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;

3. USING 子句,如果连接的两个表连接条件的两个列具有相同的名字的话可以使用 USING

例如:

SELECT FROM LEFT JOIN USING ()

连接多于两个表的情况举例:

SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;

执行结果:

mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id;
+----------+-------+------------+
| username | name  | title      |
+----------+-------+------------+
| junxi    | 君惜  | 中国有嘻哈 |
| tangtang | 糖糖  | 星光大道   |
| ceshi3   | 测试 3 | 平凡的真谛 |
| junxi    | 君惜  | Python 进阶 |
| ceshi3   | NULL  | NULL       |
| ceshi3   | NULL  | NULL       |

或者

SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (articles.user_id IS NOT NULL AND userinfos.user_id IS NOT NULL);

执行结果:

mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (articles.user_id IS NOT NULL AND userinfos.user_
id IS NOT NULL);
+----------+-------+------------+
| username | name  | title      |
+----------+-------+------------+
| junxi    | 君惜  | 中国有嘻哈 |
| tangtang | 糖糖  | 星光大道   |
| ceshi3   | 测试 3 | 平凡的真谛 |
| junxi    | 君惜  | python 进阶 |
+----------+-------+------------+

或者

SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (userinfos.name = '君惜');

执行结果:

mysql> SELECT users.username, userinfos.name, articles.title FROM users LEFT JOIN userinfos ON users.id = userinfos.user_id LEFT JOIN articles ON users.id = articles.user_id WHERE (userinfos.name = '君惜');
+----------+------+------------+
| username | name | title      |
+----------+------+------------+
| junxi    | 君惜 | 中国有嘻哈 |
| junxi    | 君惜 | python 进阶 |
+----------+------+------------+

另外需要注意的地方 在 MySQL 中涉及到多表查询的时候,需要根据查询的情况,想好使用哪种连接方式效率更高。

  1. 交叉连接 (笛卡尔积) 或者内连接 [INNER | CROSS] JOIN
  2. 左外连接 LEFT [OUTER] JOIN 或者右外连接 RIGHT [OUTER] JOIN 注意指定连接条件 WHERE, ON,USING.
三、MySQL 如何优化 LEFT JOIN 和 RIGHT JOIN

在 MySQL 中,A LEFT JOIN B join_condition 执行过程如下:
1)· 根据表 A 和 A 依赖的所有表设置表 B。
2)· 根据 LEFT JOIN 条件中使用的所有表 (除了 B) 设置表 A。
3)· LEFT JOIN 条件用于确定如何从表 B 搜索行。(换句话说,不使用 WHERE 子句中的任何条件)。
4)· 可以对所有标准连接进行优化,只是只有从它所依赖的所有表读取的表例外。如果出现循环依赖关系,MySQL 提示出现一个错误。
5)· 进行所有标准 WHERE 优化。
6)· 如果 A 中有一行匹配 WHERE 子句,但 B 中没有一行匹配 ON 条件,则生成另一个 B 行,其中所有列设置为 NULL。
7)· 如果使用 LEFT JOIN 找出在某些表中不存在的行,并且进行了下面的测试:WHERE 部分的 col_name IS NULL,其中 col_name 是一个声明为 NOT NULL 的列,MySQL 找到匹配 LEFT JOIN 条件的一个行后停止 (为具体的关键字组合) 搜索其它行。
RIGHT JOIN 的执行类似 LEFT JOIN,只是表的角色反过来。

连接优化器计算表应连接的顺序。LEFT JOIN 和 STRAIGHT_JOIN 强制的表读顺序可以帮助连接优化器更快地工作,因为检查的表交换更少。请注意这说明如果执行下面类型的查询,MySQL 进行全扫描 b,因为 LEFT JOIN 强制它在 d 之前读取:

SELECT * FROM a,b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;  

在这种情况下修复时用 a 的相反顺序,b 列于 FROM 子句中:

SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;

MySQL 可以进行下面的 LEFT JOIN 优化:如果对于产生的 NULL 行,WHERE 条件总为假,LEFT JOIN 变为普通联接。
例如,在下面的查询中如果 t2.column1 为 NULL,WHERE 子句将为 false:

SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;

因此,可以安全地将查询转换为普通联接:

SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;  

这样可以更快,因为如果可以使查询更佳,MySQL 可以在表 t1 之前使用表 t2。为了强制使用表顺序,使用 STRAIGHT_JOIN。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-10/147568.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计8106字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7802973
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站-手机博物馆-CHAZ 3D Experience

每天一个好玩的网站 - 手机博物馆 -CHAZ 3D Experience 一句话介绍:一个用 3D 方式重温...
星哥带你玩飞牛NAS-8:有了NAS你可以干什么?软件汇总篇

星哥带你玩飞牛NAS-8:有了NAS你可以干什么?软件汇总篇

星哥带你玩飞牛 NAS-8:有了 NAS 你可以干什么?软件汇总篇 前言 哈喽各位玩友!我是是星哥,不少朋友私...
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
免费领取huggingface的2核16G云服务器,超简单教程

免费领取huggingface的2核16G云服务器,超简单教程

免费领取 huggingface 的 2 核 16G 云服务器,超简单教程 前言 HuggingFace.co...
这个开源软件130k的star数!让电脑轻松管理安卓手机的神器

这个开源软件130k的star数!让电脑轻松管理安卓手机的神器

这个开源软件 130k 的 star 数!让电脑轻松管理安卓手机的神器 大家好,我是星哥。今天给大家安利一款宝...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛 NAS-5:飞牛 NAS 中的 Docker 功能介绍 大家好,我是星哥,今天给大家带来如何在...
如何免费使用强大的Nano Banana Pro?附赠邪修的用法

如何免费使用强大的Nano Banana Pro?附赠邪修的用法

如何免费使用强大的 Nano Banana Pro?附赠邪修的用法 前言 大家好,我是星哥,今天来介绍谷歌的 ...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的 NAS 中! 大家对「数据安全感」的需求越来越高 ...
150元打造低成本NAS小钢炮,捡一块3865U工控板

150元打造低成本NAS小钢炮,捡一块3865U工控板

150 元打造低成本 NAS 小钢炮,捡一块 3865U 工控板 一块二手的熊猫 B3 工控板 3865U,搭...