inner join 和 exists 效率_19 个让 MySQL 效率提高 3 倍的 SQL 优化技巧
在介绍具体的 SQL
调优的方法前,我们先来简单了解下 MySQL
调优金字塔理论。
如上图所示,数据库优化维度有四个:硬件、系统配置、数据库表结构、SQL
及索引。
优化成本:
硬件>系统配置>数据库表结构>SQL及索引
优化效果:
硬件
我们可以看出数据库 SQL 语句效率调优是最省成本效果最好的办法,也就是结构设计上的优化。
本文我们就来谈谈 MySQL 中常用的 SQL 优化方法,利用好这些方法会让你的 MySQL 效率提高提升至少 3 倍。
1、EXPLAIN
做 MySQL
优化,我们要善用 EXPLAIN
查看 SQL
执行计划。
下面来个简单的示例,标注(1、2、3、4、5)我们要重点关注的数据:
•Type 列,连接类型。一个好的 SQL 语句至少要达到 Range 级别。杜绝出现 All 级别。•Key 列,使用到的索引名。如果没有选择索引,值是 NULL。可以采取强制索引方式。•Key_Len 列,索引长度。•Rows 列,扫描行数。该值是个预估值。•Extra 列,详细说明。注意,常见的不太友好的值,如下:Using filesort,Using temporary。
2、SQL 语句中 IN 包含的值不应过多
MySQL 对于 IN
做了相应的优化,即将 IN
中的常量全部存储在一个数组里面,而且这个数组是排好序的。但是如果数值较多,产生的消耗也是比较大的。
再例如:Select Id From T where Num IN (1,2,3)
对于连续的数值,能用 Between
就不要用 IN
了;再或者使用连接来替换。
3、Select 语句务必指明字段名称
Select *
会增加很多不必要的消耗(如:CPU、IO、内存、网络带宽等), 增加了使用覆盖索引的可能性。
当表结构发生改变时,前断也需要更新。所以要求直接在 Select
后面接上字段名。
4、当只需要一条数据的时候,使用 Limit 1
这是为了使 EXPLAIN
中 Type
列达到 Const
类型。
5、如果排序字段没有用到索引,就尽量少排序
6、如果限制条件中其他字段没有索引,尽量少用 OR
OR
两边的字段中,如果有一个不是索引字段,而其他条件也不是索引字段,会造成该查询不走索引的情况。很多时候使用 Union All
或者是 Union
(必要的时候)的方式来代替 OR
会得到更好的效果。
7、尽量用 Union All 代替 Union
Union
和 Union All
的差异主要是前者需要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,增加大量的 CPU 运算,加大资源消耗及延迟。当然,Union All
的前提条件是两个结果集没有重复数据。
8、不使用 ORDER BY RAND()
Select Id From `dynamic` Order By rand() Limit 1000;
上面的 SQL
语句,可优化为:
Select Id From `dynamic` T1 Join (Select rand() * (Select Max(Id) From `dynamic`) as nid) T2 on T1.Id > T2.nidlimit 1000;
9、区分 IN 和 Exists、Not In 和 Not Exists
Select * From 表A Where Id IN (Select Id From 表B)
上面 SQL
语句相当于
Select * From 表A Where Exists(Select * From 表B Where 表B.Id=表A.Id)
区分 IN
和 Exists
主要是造成了驱动顺序的改变(这是性能变化的关键)。如果是 Exists
,那么以外层表为驱动表,先被访问,如果是 IN
,那么先执行子查询。所以 IN
适合于外表大而内表小的情况,Exists
适合于外表小而内表大的情况。
关于 Not IN
和 Not Exists
,推荐使用 Not exists
。这不仅仅是效率问题,Not IN
可能存在逻辑问题。
如何高效的写出一个替代 not in
的 SQL
语句?
原 SQL
语句:
Select Colname … From A 表 Where A.id Not IN (Select B.id From B表)
高效的 SQL
语句:
Select Colname … From A表 Left join B表 ON Where A.id = B.id Where B.id is Null
取出的结果集如下图表示,A 表不在 B 表中的数据:
10、使用合理的分页方式以提高分页的效率
Select Id,Name From Product Limit 866613, 20
使用上述 SQL
语句做分页的时候,可能有人会发现,随着表数据量的增加,直接使用 Limit
分页查询会越来越慢。
优化的方法如下:可以取前一页的最大行数的 Id ,然后根据这个最大的 Id 来限制下一页的起点。比如:此列中,上一页最大的 Id 是 866612。SQL 可以采用如下的写法:
Select Id,Name From Product Where Id> 866612 Limit 20
11、分段查询
在一些用户选择页面中,可能一些用户选择的时间范围过大,造成查询缓慢。主要的原因是扫描行数过多。这个时候可以通过程序,分段进行查询,循环遍历,将结果合并处理进行展示。
如下图这个 SQL
语句,扫描的行数成百万级以上的时候就可以使用分段查询:
12、避免在 Where 子句中对字段进行 Null 值判断
对于 Null
的判断会导致引擎放弃使用索引而进行全表扫描。
13、不建议使用 % 前缀模糊查询
例如:Like "%name"
或者 Like "%name%"
,这种查询会导致索引失效而进行全表扫描。但是可以使用 Like "name%"
。那如何要查询 %name%
呢?
如下图所示,虽然给 secret
字段添加了索引,但在 EXPLAIN
结果并没有使用。
那么如何解决这个问题呢,答案:使用全文索引。
在我们查询中经常会用到 Select id,fnum,fdst from dynamic_201606 where user_name like '%zhangsan%';
这样的语句,普通索引是无法满足查询需求的。庆幸的是在 MySQL
中,有全文索引来帮助我们。
创建全文索引的 SQL
语法是:
ALTER TABLE `dynamic_201606` ADD FULLTEXT INDEX `idx_user_name` (`user_name`);
使用全文索引的 SQL
语句是:
Select id,fnum,fdst From dynamic_201606 where match(user_name) against('zhangsan' in boolean mode);
注意:在需要创建全文索引之前,请联系 DBA 确定能否创建。同时需要注意的是查询语句的写法与普通索引的区别。
14、避免在 Where 子句中对字段进行表达式操作
比如下面这个例子:
Select user_id,user_project from user_base Where age*2=36;
在上述 SQL
中对字段就行了算术运算,这会造成引擎放弃使用索引,建议改成:
Select user_id,user_project from user_base where age=36/2;
15、避免隐式类型转换
Where
子句中出现 Column
字段的类型和传入的参数类型不一致的时候发生的类型转换,建议先确定 Where 中的参数类型。
16、对于联合索引来说,要遵守最左前缀法则
举列来说:索引含有字段 id、name、school,可以直接用 id 字段,也可以 id、name 这样的顺序,但是 name,school 都无法使用这个索引。所以在创建联合索引的时候一定要注意索引字段顺序,常用的查询字段放在最前面。
17、必要时可以使用 Force Index 来强制查询走某个索引
有的时候 MySQL
优化器采取它认为合适的索引来检索 SQL
语句,但是可能它所采用的索引并不是我们想要的。这时就可以采用 Force index
来强制优化器使用我们制定的索引。
18、注意范围查询语句
对于联合索引来说,如果存在范围查询,比如 Between
、>
、<
等条件时,会造成后面的索引字段失效。
19、关于 JOIN 优化
LEFT JOIN
A 表为驱动表,INNER JOIN
MySQL 会自动找出那个数据少的表作用驱动表,RIGHT JOIN
B表为驱动表。
注意:
•MySQL 中没有 Full Join
,可以用以下方式来解决:
Select * from A left join B on B.name = A.namewhere B.name is nullunion allselect * from B;
•尽量使用 Inner Join
,避免 Left Join
参与联合查询的表至少为 2 张表,一般都存在大小之分。如果连接方式是 Inner Join
,在没有其他过滤条件的情况下 MySQL 会自动选择小表作为驱动表。但是 Left Join
在驱动表的选择上遵循的是左边驱动右边的原则,即 Left join
左边的表名为驱动表。
•合理利用索引
被驱动表的索引字段作为 ON
的限制字段。
•利用小表去驱动大表
从原理图能够直观的看出如果能够减少驱动表的话,减少嵌套循环中的循环次数,以减少 IO 总量及 CPU 运算的次数。
•巧用 STRAIGHT_JOIN
Inner Join
是由 MySQL
选择驱动表,但是有些特殊情况需要选择另外的表作为驱动表。比如:Group By
、Order By
等 「Using filesort」、「Using temporary」时。
用来强制连接顺序,在
STRAIGHT_JOINSTRAIGHT_JOIN
左边的表名就是驱动表,右边则是被驱动表。在使用 STRAIGHT_JOIN
有个前提条件是该查询是内连接,也就是 Inner Join
。其他连接不推荐使用 STRAIGHT_JOIN
,否则可能造成查询结果不准确。
使用这个方式有时能减少 3 倍左右的时间。
来源:知乎
原文:http://t.cn/EJXXI1H题图:来自谷歌图片搜索
版权:本文版权归原作者所有
今日思想
Freedom is not letting you do whatever you wanna but teaching you not to do the things you don't wanna do.
自由不是让你想做什么就做什么,自由是教你不想做什么,就可以不做什么。
—— 伊曼努尔·康德
推荐阅读
图解 Docker 架构
IPv6 入门教程
谈谈监控那些事
浅谈 MySQL 优化实施方案
腾讯正式发布 TCP 单边拥塞控制算法 TCPA,比 Google BBR 速度提升 40% (附安装教程)
inner join 和 exists 效率_19 个让 MySQL 效率提高 3 倍的 SQL 优化技巧相关推荐
- inner join 和 exists 效率_19条效率至少提高3倍的MySQL技巧
点击蓝色"程序猿DD"关注我哟 加个"星标",不忘签到哦 来源:https://zhuanlan.zhihu.com/p/49888088 关注我,回复口令获取 ...
- inner join 和 exists 效率_一阵骚操作,我把SQL执行效率提高了10000000倍!
作者:风过无痕-唐 http://www.cnblogs.com/tangyanbo/p/4462734.html 场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表: create ...
- inner join 和 exists 效率_一个in、exists、join的简单测试
创建两张表先单独插入两条数据 然后批量插入部门号为10,20,30,40的数据各10499099条 然后dept表也插些干扰数据 测试语句 开始验证in和exists和join 先比较个占比多的部门, ...
- mysql exists 效率_Mysql之exists和inner join效率问题(1)
使用两张大小差距比较大的表来进行测试 前言:在使用laravel的过程中发现whereHas实现的方式是exists子查询,又听说exists尽量少使用,容易导致慢查询,于是就有了接下来两篇文章. 两 ...
- mysql sql left right inner join区别及效率比较
一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona table1 ...
- sql中 in , not in , exists , not exists效率分析
in和exists执行时,in是先执行子查询中的查询,然后再执行主查询.而exists查询它是先执行主查询,即外层表的查询,然后再执行子查询. exists 和 in 在执行时效率单从执行时间来说差不 ...
- SQL优化——IN和EXISTS谁的效率更高
.点击上方"蓝字" 关注我们,享更多干货! IN和EXISTS被频繁使用在SQL中,虽然作用是一样的,但是在使用效率谁更高这点上众说纷纭.下面我们就通过一组测试来看,在不同场景下, ...
- 【Hive】left semi join(exists、in)和 left join 区别
left semi join(exists.in)和 left join 区别 left semi join 基本认识 对比 执行计划 小结 left semi join 基本认识 LEFT SEMI ...
- SQL 在Join 和 Exists查询时对Null 值的处理
文章目录 Join 中 null 值的处理 In 和 Exists 中 null 值的处理 Join 和 Exists 测试 准备测试数据 Join 测试 In 和 Exists 测试 最近发现SQL ...
最新文章
- VS Code 离线安装插件方法
- hihoCoder#1384 : Genius ACM
- gis 大屏_胡中南:Web端GIS技术新进展 | (PPT+速记)
- 拥抱单页网站! jQuery全屏滚动插件fullPage.js
- [占坑] 近几天正在准备的文章
- python3列表_Python3列表
- 二分查找(划分时左右元素个数不相等)解析+代码
- java 原子类_小学妹教你并发编程的三大特性:原子性、可见性、有序性
- 特斯拉下一代Roadster跑车生产时间再度推迟至2023年
- 18. 树的子结构(C++版本)
- JavaWeb:生成简单随机图片验证码返回给客户端
- angularJS(二):作用域$scope、控制器、过滤器
- 面试技巧 面试复盘 编程技术 架构 看这一篇就够了
- python中temp是什么意思中文-请问Python里temp是什么意思?
- ubuntu18.4解决问题: Installation failed. See log at /var/log/cuda-installer.log for details.
- 计算机竞赛 自主招生,2017年自主招生认可的竞赛汇总
- 谷歌浏览器崩溃,提示 “STATUS_INVALID_IMAGE_HASH” 的解决办法
- 示例程序:关于双目视觉,标定,立体匹配(视差算法),点云,双目三维重建的原理以及代码
- 微软所有正版软件下载网站ITELLYOU_我是亲民_新浪博客
- 我们正处于并将长期处于从“艺工交叉”到“自我创造”的过渡阶段