MySQL优化系列(二)--查找优化(2)(外连接、多表联合查询以及查询注意点)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDSClaw,2核4GB
简介: MySQL优化系列(二)--查找优化(2)(外连接、多表联合查询以及查询注意点) 继续这一系列,上篇的简单查询优化并没讲完,第二点还有查询注意点以及多表查询优化呢!! 文章结构:(1)多表查询步步优化;(2)查询编写的注意点。

MySQL优化系列(二)--查找优化(2)(外连接、多表联合查询以及查询注意点)

继续这一系列,上篇的简单查询优化并没讲完,第二点还有查询注意点以及多表查询优化呢!!
文章结构:(1)多表查询步步优化;(2)查询编写的注意点。
/*
    补充说明(往后有博友反馈的话,会继续补充。)
*/

一、2017-7-19:
关于“超大型数据尽可能尽力不要写子查询,使用连接(JOIN)去替换它”。
关于这一类的总结,我们要认真去考量,这里并不是说一定。
1)因为在大型的数据处理中,子查询是非常常见的,特别是在查询出来的数据需要进一步处理的情况,无论是可读性还是效率上,这时候的子查都是更优。
2)然而在一些特定的场景,可以直接从数据库读取就可以的,比如一个表(A表 a,b,c字段,需要内部数据交集)join自己的效率必然比放一个子查在where中快得多。可参见我给的例子中的拉黑表,好友表(双方互相喜欢才是好友的表),在查自己的好友列表的时候,或者拉黑列表中。
1
2
3
4
5
6
7
8
9
本系列:demo下载
(一)MySQL优化笔记(一)–库与表基本操作以及数据增删改
(二)MySQL优化笔记(二)–查找优化(1)(非索引设计)
(三)MySQL优化笔记(二)–查找优化(2)(外连接、多表联合查询以及查询注意点)
(四) MySQL优化笔记(三)–索引的使用、原理和设计优化
(五) MySQL优化笔记(四)–表的设计与优化(单表、多表)
(六)MySQL优化笔记(五)–数据库存储引擎
文章目录:
(1)多表查询步步优化
基本连接方法(内连接、外连接以及交叉连接)

内连接:用比较运算符根据每个表共有的列的值匹配两个表中的行(=或>、<)
外连接之左连接
外连接之右连接
外连接之全外连接
交叉连接
超大型数据尽可能尽力不要写子查询,使用连接(JOIN)去替换它(基础讲完,讲优化)

(3)使用联合(UNION)来代替手动创建的临时表
建立索引(下一篇将详讲)
(2)查询编写的注意点
大概有9点,详情见下文。
一、多表查询步步优化:(使用还是之前的数据库的表,商品分类表以及商品详情表)


给出的数据库有基本的数据框架,剩下的几个假数据我们就自己创建吧。注意此两表是有外键约束的。


(1)基本连接方法(内连接、外连接以及交叉连接):
一)内连接:用比较运算符根据每个表共有的列的值匹配两个表中的行(=或>、<)
//意思是:检索商品分类表和商品表“分类描述”相同的行
select
        d.Good_ID ,
        d.Classify_ID,
        d.Good_Name
        from
        Commodity_list d
        inner join commodity_classification c
        on d.Classify_Description=c.Good_kinds_Name
1
2
3
4
5
6
7
8
9
10
得到的满足某一条件的是A,B内部的数据;正因为得到的是内部共有数据,所以连接方式称为内连接。


很容器看出是两者都满足才查出


二)外连接之左连接
//意思:查得商品分类表的所有数据,以及满足条件的商品详情表的数据
select
        *
        from
        commodity_classification c
        left join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
1
2
3
4
5
6
7


可以看到,首先是左表数据全部罗列,然后有满足条件的右表数据都会全部罗列出。若两条右表数据对左表一条数据,则会用对应好的左表数据补足作为一条记录。


左连接升级:
[left join 或者left outer join(等同于left join)] + [where B.column is null]
//就是只查分类表数据,但是减去跟商品详情表有联系的数据。
select
        *
        from
        commodity_classification c
        left join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
        where d.Classify_Description is null
1
2
3
4
5
6
7
8
9
 


三)外连接之右连接
//意思是查得商品详情表的所有数据以及在分类描述相同条件下的商品分类表数据
select
        *
        from
        commodity_classification c
        right join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
1
2
3
4
5
6
7
8


与左连恰恰相反,首先是右表数据全部罗列,然后有满足条件的左表数据都会全部罗列出。若两条左表数据对右表一条数据,则会用对应好的右表数据补足作为一条记录。


右连接升级:
//意思:查询商品详情表的所有数据,但是要减去和商品分类表有联系的数据
select
        *
        from
        commodity_classification c
        right join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
        where c.Good_kinds_Name is null  
1
2
3
4
5
6
7
8
9


四)外连接之全外连接:
full join (mysql不支持,但是可以用 left join union right join代替)
select
        *
        from
        commodity_classification c
        left join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
        union
select
        *
        from
        commodity_classification c
        right join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
1
2
3
4
5
6
7
8
9
10
11
12
13
这种场景下得到的是满足某一条件的公共记录,和独有的记录


全外连接升级:
select
        *
        from
        commodity_classification c
        left join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
        where d.Classify_Description is null
        union
select
        *
        from
        commodity_classification c
        right join commodity_list d
        on d.Classify_Description=c.Good_kinds_Name
         where c.Good_kinds_Name is null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
这种场景下得到的是A,B中不满足某一条件的记录之和.


全部一起列出:消除重复项


五)交叉连接:
交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。 FROM 子句中的表或视图可通过内联接或完整外部联接按任意顺序指定;但是,用左或右向外联接指定表或视图时,表或视图的顺序很重要。有关使用左或右向外联接排列表的更多信息,请参见使用外联接。
有两种情况,显式的和隐式的,不带ON子句,返回的是两表的乘积,也叫笛卡尔积。
1. 第一种方式(显式的交叉连接):A,B表记录的排列组合,即笛卡儿积。
//可以看到
select
        *
        from
        commodity_classification c
       cross join commodity_list d 
1
2
3
4
5
6


补充:cross join可指定条件 (where)
select
        *
        from
        commodity_classification c
       cross join commodity_list d 
       where c.Good_kinds_Name=d.Classify_Description
1
2
3
4
5
6
相当于实现内连接功能了。


2. 第二种方式:(隐式的交叉连接,没有CROSS JOIN)
就跟正上面的效果一样的语句啦!
select
        *
        from
        commodity_classification c,
        commodity_list d 
       where c.Good_kinds_Name=d.Classify_Description
1
2
3
4
5
6
交叉连接存在的问题遗漏: 参考此博主此博文
mysql对sql语句的容错问题,即在sql语句不完全符合书写建议的情况,mysql会允许这种情况,尽可能解释它:
1)一般cross join后面加上where条件,但是用cross join+on也是被解释为cross join+where;
2)一般内连接都需要加上on限定条件,如上面场景一;如果不加会被解释为交叉连接;
3)如果连接表格使用的是逗号,会被解释为交叉连接;
注:sql标准中还有union join和natural inner join,mysql不支持,而且本身也没有多大意义,其结果可以用上面的几种连接方式得到。
(2)超大型数据尽可能尽力不要写子查询,使用连接(JOIN)去替换它(基础讲完,讲优化):
子查询:
定义:在一个表表达中可以调用另一个表表达式,这个被调用的表表达式叫做子查询(subquery),也称作子选择(subselect)或内嵌选择(inner select)。子查询的结果传递给调用它的表表达式继续处理。
//很简单的意思:就是根据商品id查商品详情表,然后用查出来的ID去查商品分类表。
select
       *
       from
       commodity_classification c  
       where Classify_ID  IN(select Classify_ID from commodity_list where Good_ID='tb10025584930')
1
2
3
4
5
6
使用JOIN进行优化:
select
       *
       from
       commodity_classification c  
       left join commodity_list d on d.Classify_ID=c.Classify_ID
       where d.Good_ID='tb10025584930'
1
2
3
4
5
6
7
(3)使用联合(UNION)来代替手动创建的临时表
UNION是会把结果排序的!!!
union查询,它可以把需要使用临时表的两条或更多的select查询合并的一个查询中(即把两次或多次查询结果合并起来。)。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。
#

要求:两次查询的列数必须一致
推荐:列的类型可以不一样,但推荐查询的每一列,想对应的类型以一样
可以来自多张表的数据:多次sql语句取出的列名可以不一致,此时以第一个sql语句的列名为准。
如果不同的语句中取出的行,有完全相同(这里表示的是每个列的值都相同),那么union会将相同的行合并,最终只保留一行。也可以这样理解,union会去掉重复的行。
如果不想去掉重复的行,可以使用union all。
如果子句中有order by,limit,需用括号()包起来。推荐放到所有子句之后,即对最终合并的结果来排序或筛选。
select
       Classify_ID,Good_kinds_Name
       from
       commodity_classification 
       union
select 
        Classify_ID,Classify_Description
        from 
        commodity_list

//加条件
(select
       Classify_ID,Good_kinds_Name
       from
       commodity_classification 
       order by Classify_ID)
       union
(select 
        Classify_ID,Classify_Description
        from 
        commodity_list
        order by Good_ID)

//经常操作的含义:列出所有在中国和美国的不同的雇员名
SELECT E_Name FROM Employees_China
UNION
SELECT E_Name FROM Employees_USA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
注意:
1、UNION 结果集中的列名总是等于第一个 SELECT 语句中的列名
2、UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同
UNION ALL的作用和语法:
默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。当 ALL 随 UNION 一起使用时(即 UNION ALL),不消除重复行。
select
       Classify_ID,Good_kinds_Name
       from
       commodity_classification 
       union ALL
select 
        Classify_ID,Classify_Description
        from 
        commodity_list
1
2
3
4
5
6
7
8
9
不删除重复数据


(4)建立索引(下一篇将详讲)
二、查询编写的注意点:
(1)对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。(索引的注意点在下篇将详讲)
(2)应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
//最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.
select id from t where num is null
1
2
备注、描述、评论之类的可以设置为 NULL,其他最好不要使用NULL。
不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num = 0
1
(3)in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
1
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
1
很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
1
//用这个去替换
select num from a where exists(select 1 from b where num=a.num)
1
2
(4)下面的查询也将导致全表扫描:
select id from t where name like ‘%abc%’
1
若要提高效率,可以考虑全文检索。
(5)尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
(6)任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
(7)尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
(8)在Join表的时候使用相当类型的例,并将其索引
如果你的应用程序有很多 JOIN 查询,你应该确认两个表中Join的字段是被建过索引的。这样,MySQL内部会启动为你优化Join的SQL语句的机制。
而且,这些被用来Join的字段,应该是相同的类型的。例如:如果你要把 DECIMAL 字段和一个 INT 字段Join在一起,MySQL就无法使用它们的索引。对于那些STRING类型,还需要有相同的字符集才行。(两个表的字符集有可能不一样)
//在state中查找company
SELECT company_name FROM users
    LEFT JOIN companies ON (users.state = companies.state)
    WHERE users.id = $user_id"
    //两个 state 字段应该是被建过索引的,而且应该是相当的类型,相同的字符集
1
2
3
4
5
(9)查询索引中的sql语句有很多讲究,在下篇文章我们将详细讨论。
源码下载:数据库文件下载
好了,MySQL优化系列(二)–查找优化(2)(外连接、多表联合查询以及查询注意点)讲完了,下一篇就是我们的索引详讲了,很难又很重要关键,性能的关键点,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!
更多内容,可以访问JackFrost的博客
--------------------- 
作者:Jack__Frost 
来源:CSDN 
版权声明:本文为博主原创文章,转载请附上博文链接!
相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
7月前
|
SQL 缓存 监控
MySQL缓存机制:查询缓存与缓冲池优化
MySQL缓存机制是提升数据库性能的关键。本文深入解析了MySQL的缓存体系,包括已弃用的查询缓存和核心的InnoDB缓冲池,帮助理解缓存优化原理。通过合理配置,可显著提升数据库性能,甚至达到10倍以上的效果。
|
7月前
|
SQL 存储 关系型数据库
MySQL体系结构详解:一条SQL查询的旅程
本文深入解析MySQL内部架构,从SQL查询的执行流程到性能优化技巧,涵盖连接建立、查询处理、执行阶段及存储引擎工作机制,帮助开发者理解MySQL运行原理并提升数据库性能。
|
7月前
|
SQL 关系型数据库 MySQL
MySQL的查询操作语法要点
储存过程(Stored Procedures) 和 函数(Functions) : 储存过程和函数允许用户编写 SQL 脚本执行复杂任务.
302 14
|
7月前
|
SQL 关系型数据库 MySQL
MySQL的查询操作语法要点
以上概述了MySQL 中常见且重要 的几种 SQL 查询及其相关概念 这些知识点对任何希望有效利用 MySQL 进行数据库管理工作者都至关重要
199 15
|
7月前
|
SQL 监控 关系型数据库
SQL优化技巧:让MySQL查询快人一步
本文深入解析了MySQL查询优化的核心技巧,涵盖索引设计、查询重写、分页优化、批量操作、数据类型优化及性能监控等方面,帮助开发者显著提升数据库性能,解决慢查询问题,适用于高并发与大数据场景。
|
7月前
|
SQL 关系型数据库 MySQL
MySQL入门指南:从安装到第一个查询
本文为MySQL数据库入门指南,内容涵盖从安装配置到基础操作与SQL语法的详细教程。文章首先介绍在Windows、macOS和Linux系统中安装MySQL的步骤,并指导进行初始配置和安全设置。随后讲解数据库和表的创建与管理,包括表结构设计、字段定义和约束设置。接着系统介绍SQL语句的基本操作,如插入、查询、更新和删除数据。此外,文章还涉及高级查询技巧,包括多表连接、聚合函数和子查询的应用。通过实战案例,帮助读者掌握复杂查询与数据修改。最后附有常见问题解答和实用技巧,如数据导入导出和常用函数使用。适合初学者快速入门MySQL数据库,助力数据库技能提升。
|
8月前
|
存储 关系型数据库 MySQL
使用命令行cmd查询MySQL表结构信息技巧分享。
掌握了这些命令和技巧,您就能快速并有效地从命令行中查询MySQL表的结构信息,进而支持数据库维护、架构审查和优化等工作。
745 9
|
8月前
|
缓存 关系型数据库 MySQL
降低MySQL高CPU使用率的优化策略。
通过上述方法不断地迭代改进,在实际操作中需要根据具体场景做出相对合理判断。每一步改进都需谨慎评估其变动可能导致其他方面问题,在做任何变动前建议先在测试环境验证其效果后再部署到生产环境中去。
344 6
|
7月前
|
SQL 监控 关系型数据库
MySQL高级查询技巧:子查询、联接与集合操作
本文深入解析了MySQL高级查询的核心技术,包括子查询、联接和集合操作,通过实际业务场景展示了其语法、性能差异和适用场景,并提供大量可复用的代码示例,助你从SQL新手进阶为数据操作高手。
|
9月前
|
存储 SQL 关系型数据库
MySQL 动态分区管理:自动化与优化实践
本文介绍了如何利用 MySQL 的存储过程与事件调度器实现动态分区管理,自动化应对数据增长,提升查询性能与数据管理效率,并详细解析了分区创建、冲突避免及实际应用中的关键注意事项。
403 0

推荐镜像

更多