MySQL之SQL语句优化
语句优化
即优化器利用自身的优化器来对我们写的SQL进行优化,然后再将其放入InnoDB引擎中执行。
条件简化
移除不必要的括号
select * from x where ((a = 5));
上面的括号很没必要,优化器就会直接去掉。
select * from x where a = 5;
等值传递
select * from x where b = a and a = 5;
同样的,虽然是两列比较,但是a的值只有一个,所以可以优化
select * from x where b = 5 and a = 5;
常量传递
select * from x where a = 5 and b > a;
可以优化为
select * from x where a = 5 and b > 5;
移除没用的条件
select * from x where a < 5 and b > 10 and b > a;
当前两个条件发生时,最后一个条件必然发生,所以可以优化
select * from x where a < 5 and b > 10;
表达式计算
select * from x where -a > -5;
优化器不会对其进行优化,而且这个坏处很多就是不能使用索引了,所以我们尽量让列单独出现,而不是在表达式计算中。
常量表检测
当表中只有一两条数据,或则使用主键或唯一列的索引等值查询的话就会被MySQL优化器视为常量表,直接将SQL语句优化成常量。
select * from table1 join table2 on table1.col1 = table2.col2 where table1 = 'a';
select table1的列都作为常量,table2.* from table2 where table1的常量col1 = table2.col2;
外连接消除
外连接呢,首先连接的顺序是固定的,故驱动表和被驱动表是固定不变的。所以是不能像内连接一样交换驱动表的。
但是呢,有一种情况
select * from table1 left join table2 on table1.col1 = table2.col2 where table2.col2 is not null;
我们设定了table2的列是非空的,这意味着什么,当table1匹配不到时设置table2列为null,但是却不满足搜索条件被过滤掉,所以左连接匹配失败null相当于是失效的。这个语句和内连接是没有区别的,直接将其优化为内连接即可。
所以当在外连接出现时,但是被驱动表拒绝空值时,此时外连接和内连接是可以互相转换的,而内连接可以通过交换驱动表来优化SQL查询成本。
子查询优化
子查询分类
- 标量子查询
- 列子查询
- 行子查询
- 表子查询
再分
- 相关子查询
- 不相关子查询
标量子查询
不相关标量子查询
select * from x where key1 = (select y.key1 from y where y.primarykey = 1);
对于不相关的标量子查询来说,就是先执行子查询,然后在对外部查询进行查询。
相关子查询
select * from s1 where key1 = (select common_field from s2 where s1.key3 = s2.key3 limit 1);
对于相关的标量子查询
- 首先取出外部的每条满足自身搜索条件的行,然后传入子查询对应列的值。
- 计算子查询的结果
- 在判断外部key1对于这个子查询给的结果是否满足条件,满足加入结果行。
- 继续循环回1,直到遍历完所有外层表的行。
其实和连接的流程差不多。
优化器对于标量的子查询并不需要什么优化,因为对于标量的子查询来说,数据量还算很小的了。
IN子查询优化
select * from x where key1 in (select key3 from y);
对于上述不相关的IN查询来说,如果IN子查询的参数少的话,还可以试着加载到内存,然后让外层查询对很多的条件进行比较。
但是如果子查询数据量一旦大了起来,内存无法全部加载完,或导致外层查询需要比较的参数太多,外层记录需要对于过多条件进行比较,导致索引无法使用,因为每一次都要使用索引,每次都要比较,还不如直接全表扫描。最后导致性能很低。
物化表优化
MySQL对这种in参数过多时,不会将子查询在作为外部的参数,而是直接创建一个临时表来存储子查询的结果。
- 将临时表的列为子查询结果的列,并对其进行去重。
- 临时表经过去重通常不会太大,创建的是Memory的存储引擎的临时表,并对其创建哈希索引。
子查询转物化表materialized_table后,我们还能将物化表和外层查询转换为连接的方式。
select x.* from x inner join materialized_table m on key1 = m.key3;
然后我们就可以用之前计算成本的知识来计算那个作为驱动表更合适了。
只有不相关子查询才能转换为物化表
semi-join优化
像上述结果一样,我们将查询结果转换为物化表,然后我们在把物化表转换为连接的方式。
我们为什么不能直接将子查询转换为连接的方式呢?这就是semi-join优化。
我们可以试试将其转换为如下语句
select x.* from x join y on key1 = key3;
三种情况
- 被驱动表y的行不满足连接条件的,不能加入结果集。
- 被驱动表y一个key3满足和驱动表x的key1相等且y表key3有且仅有一条,有一条记录加入结果集。
- 被驱动表y有key3满足连接条件但是一个key3有很多条记录,就会有多条记录加入结果集。
能满足的条件就是y表的key3是主键或唯一列,不然就会出现多条的情况,这条语句就不等于原语句了。
但是此时semi join半连接概念的出现,在半连接的情况下,对于驱动表x来说,我们只关心被驱动表y是否有记录能够满足连接条件的,而不关心被驱动表y有几条能匹配,最后结果集只保存驱动表x的记录。
实现半连接semi join的方法。PS:semi join半连接只是一个概念。
- Table pullout (子查询中表上拉)
- 当子查询的查询列 ( 即select 的列 ) 是主键或唯一列,就是我们上面说的直接join 出来即可,因为不会出现多条的情况
- DuplicateWeedout execution strategy (重复值消除策略)
- 我们不是提到上述的我们自己改为join的方法会出现重复的情况吗,因为被驱动表的重复导致驱动表的重复。
- 我们就直接创建一个临时表,把s1连接的结果记录id (是数据行的id可以这么理解把) 放入临时表中,当该数据行再次被加入时临时表就会抛出主键重复的异常,就不会加入重复行了。
- LooseScan execution strategy (松散索引扫描)
- 当子查询列key1有子查询表的索引,这样我们就可以通过索引访问,对于每个值,只访问一行,重复值不再访问,这样来防止出现多条记录。
- Semi-join Materialization execution strategy (物化表半连接)
- 将不相关子查询通过物化表的方式物化为临时表,没有重复行的情形,我们可以直接转换为连接。
- FirstMatch execution strategy (首次匹配)
- 取外连接的一条记录,然后和子查询进行一条一条的比较。最原始的方法
semi join使用条件:
- 该子查询必须是和IN语句组成的布尔表达式,并且在外层的Where和on子句中出现。
- 外层的搜索条件必须是用and 和in子查询连接的。
- 子查询是单一的查询,不能union
- 子查询不能包含group by、having、聚集函数
- ...
EXISTS优化
如果不能使用semi join和物化表,我们还可以将in的语句改造成EXISTS语句。
将上述改造为如下语句。
select * from x where exists (select 1 from y where key3 = x.key1)
如果被驱动表key3有索引,就可以使用索引了啊 o( ̄▽ ̄)d。
这个算是下下策了。
MySQL之SQL语句优化的更多相关文章
- mysql的sql语句优化方法面试题总结
mysql的sql语句优化方法面试题总结 不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这类代码不会返回任何结 ...
- php面试专题---MySQL常用SQL语句优化
php面试专题---MySQL常用SQL语句优化 一.总结 一句话总结: 原理,万变不离其宗:其实SQL语句优化的过程中,无非就是对mysql的执行计划理解,以及B+树索引的理解,其实只要我们理解执行 ...
- MySQL常用SQL语句优化
推荐阅读这篇博文,索引说的非常详细到位:http://blog.linezing.com/?p=798#nav-3-2 在数据库日常维护中,最常做的事情就是SQL语句优化,因为这个才是影响性能的最主要 ...
- MySQL 数据库--SQL语句优化
explain查询和分析sql 开发中,为满足一业务功能,使用mysql书写sql时,一条sql往往有多种写法,那么我们就需要选择执行效率比较高的sql. 因此要比较分析sql的执行过程,且同一条sq ...
- Mysql的Sql语句优化
在Mysql中执行Sql语句经常会遇到有的语句执行时间特别长的情况,出现了这种情况我们就需要静下心分析分析. 首先,我们需要确定系统中哪些语句执行时间比较长.这个可以使用Mysql的慢日志来跟踪.下面 ...
- 千万级大数据的Mysql数据库SQL语句优化
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- MySQL的SQL语句优化-group by语句的优化
原文:http://bbs.landingbj.com/t-0-243202-1.html 默认情况下,MySQL排序所有GROUP BY col1, col2, ....,查询的方法如同在查询中指定 ...
- 重新学习MySQL数据库12:从实践sql语句优化开始
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/a724888/article/details/79394168 本文不堆叠网上海量的sql优化技巧或 ...
- 浅谈mysql配置优化和sql语句优化【转】
做优化,我在这里引用淘宝系统分析师蒋江伟的一句话:只有勇于承担,才能让人有勇气,有承担自己的错误的勇气.有承担错误的勇气,就有去做事得勇气.无论做什么事,只要是对的,就要去做,勇敢去做.出了错误,承担 ...
随机推荐
- java中finally有什么意义呢,在现实中?举例
马克-to-win: finally有什么意义呢,在现实中?比如你开了一个流处理文件,可能没开成功,或开成功了,但后面的操作失败了,但不管你怎么样,你必须在一个地儿把它关闭,那就是finally块儿. ...
- .NET程序设计实验二
实验二 面向对象程序设计 一.实验目的 1. 理解类的定义.继承等面向对象的的基本概念: 2. 掌握C#语言定义类及其各种成员(字段,属性,方法)的方法: 3. 掌握方法覆盖的应用: 4. 掌握接口 ...
- ruby 版本管理RVM (ruby version manager)
macOS. 自带的ruby 版本目录权限比较高, 经常有很多 操作需要权限而不能执行 虽然 macOS 自带了一个 ruby 环境,但是是系统自己使用的,所以权限很小,只有 system. 而/Li ...
- 正则表达式小技巧,sql中in的字符串处理
工作中我经常写sql,当写带in的语句时,需要敲好多单引号,逗号,敲写起来容易易出错.因此,我写了一个小工具,处理这种繁琐工作.原理简单,利用正则表达式匹配.替换. 先看界面,一个html页面,包含三 ...
- drf过滤和排序及异常处理的包装
过滤和排序(4星) 查询所有才需要过滤(根据过滤条件),排序(按某个规律排序) 使用前提: 必须继承的顶层类是GenericAPIView 内置过滤类 内置过滤类使用,在视图类中配置,是模糊查询 使用 ...
- 启动jar包的shell脚本
在jar包的同级目录新建文件例如:app_jar.sh 然后填写如下内容: #!/bin/bash #source /etc/profile # Auth:Liucx # Please change ...
- iOS全埋点解决方案-UITableView和UICollectionView点击事件
前言 在 $AppClick 事件采集中,还有两个比较特殊的控件: UITableView •UICollectionView 这两个控件的点击事件,一般指的是点击 UITableViewCell 和 ...
- 内存之旅——如何提升CMA利用率?
(以下内容来自开发者分享,不代表 OpenHarmony 项目群工作委员会观点) 宋远征 李佳伟 OpenAtom OpenHarmony(以下简称"OpenHarmony") ...
- 2021年3月-第02阶段-前端基础-HTML+CSS阶段-Day03
HTML5 第三天 一. 认识 3D 转换 3D 的特点 近大远小 物体和面遮挡不可见 三维坐标系 x 轴:水平向右 -- 注意:x 轴右边是正值,左边是负值 y 轴:垂直向下 -- 注意:y 轴下面 ...
- 2021.08.16 P1260 工程规划(差分约束)
2021.08.16 P1260 工程规划(差分约束) 重点: 1.跑最短路是为了满足更多约束条件. P1260 工程规划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 造 ...