Mysql优化(出自官方文档) - 第五篇
目录
- Mysql优化(出自官方文档) - 第五篇
- 1 GROUP BY Optimization
- 2 DISTINCT Optimization
- 3 LIMIT Query Optimization
- 4 Function Call Optimization
- 5 Avoiding Full Table Scans
Mysql优化(出自官方文档) - 第五篇
1 GROUP BY Optimization
通常来讲,实现group by
的方式是创建一个临时表,然后按照group by
的列插入到临时表中,在进行后续处理,但是如果group by
的列均来自于同一个index
(唯一或者二级索引),那么Mysql
会使用index
来进行group by
处理。关于索引的使用方式,主要有两种:
Loose Index Scan
:将group by
操作和所有的range
一起来进行操作。Tight Index Scan
:首先进行range scan
,然后在对获取到的结果进行分组。
Loose Index Scan
定义:不需要扫描
group by
的所有列来满足where
条件,只需要考虑索引中的一部分来满足要求。Loose Index Scan
需要满足下面的条件:- 只针对一个表
group by
的列必须是索引leftmost
的列(如果没有group by,distrinct
也可以,且distrinct
的列也必须为leftmost
),比如,在一个表(t1,t2,t3,t4)
上有索引(t1,t2,t3)
,此时group by
的列为(t1,t2)
或者(t1)
,均适用于Loose Index Scan
,如果是(t1,t3,t4)
,那么将无法使用该优化技术。- 只支持
MIN,MAX
聚合函数,并且作用的对象都必须为同一个列,该列必须在索引里面且在group by
语句中。 select
中不在group by
的列比较对象必须为常量,包括MIN
和MAX
- 索引中的列必须完全被索引,比如:一个
c1 varchar(20)
,索引不能为c1(10)
,必须为整个长度。
在EXPLAIN输出里面,如果采用了这种优化技术,那么会显示
Using index for group-by
下面的语句均使用这种优化技术(假设
t1
表(t1,t2,t3,t4)
,有索引(t1,t2,t3)
):SELECT c1, c2 FROM t1 GROUP BY c1, c2; SELECT DISTINCT c1, c2 FROM t1; SELECT c1, MIN(c2) FROM t1 GROUP BY c1; SELECT c1, c2 FROM t1 WHERE c1 < const GROUP BY c1, c2; SELECT MAX(c3), MIN(c3), c1, c2 FROM t1 WHERE c2 > const GROUP BY c1, c2; SELECT c2 FROM t1 WHERE c1 < const GROUP BY c1, c2; SELECT c1, c2 FROM t1 WHERE c3 = const GROUP BY c1, c2;
下面的语句不适用这种情况:
- 聚合函数只支持
MIN
和MAX
:
SELECT c1, SUM(c2) FROM t1 GROUP BY c1;
group by
的列必须为leftmost
:SELECT c1, c2 FROM t1 GROUP BY c2, c3;
select中剩余的列(没有被group by包含的)必须和一个常量进行比较,下面的c3不满足:
SELECT c1, c3 FROM t1 GROUP BY c1, c2;
除了
MIN
和MAX
外,Loose Index Scan
也可以作用于其他形式的聚合函数,但是有如下限制:AVG, SUM
和COUNT
均可以支持,但是AVG, SUM
必须只有一个参数,COUNT
可以有多个参数- 不能有
GROUP BY
和DISTINCT
语句 - 文章开头的限制依旧适用于这种情况。
假设t1表(t1,t2,t3,t4)有索引(t1,t2,t3),下面的语句也可以使用与Loose Index Scan:
SELECT COUNT(DISTINCT c1), SUM(DISTINCT c1) FROM t1; SELECT COUNT(DISTINCT c1, c2), COUNT(DISTINCT c2, c1) FROM t1;
Tight Index Scan
当Loose Index Scan无法适用时,此时如果适用于Tight Index Scan,Mysql依旧不会去创建一个临时表,Tight Index Scan的定义为:如果有where条件,那么会根据索引范围直接进行扫描(index Scan),反之,会进行一个Full Index Scan。对于下面的语句,不适用于Loose Index Scan,但是依旧可以采用Tight Index Scan来进行分组:依旧假设t1表(t1,t2,t3,t4)有索引(t1,t2,t3):
- GROUP BY的列不是leftmost,但是进行Full Index Scan后,在对其进行过滤。
SELECT c1, c2, c3 FROM t1 WHERE c2 = 'a' GROUP BY c1, c3; SELECT c1, c2, c3 FROM t1 WHERE c1 = 'a' GROUP BY c2, c3;
2 DISTINCT Optimization
由于DISTINCT和GROUP BY是可以相互转换的,因此,适用于GROUP BY的情况也同样适用于DISTINCT,比如下面的语句是等价的:
SELECT DISTINCT c1, c2, c3 FROM t1
WHERE c1 > const;SELECT c1, c2, c3 FROM t1
WHERE c1 > const GROUP BY c1, c2, c3;
3 LIMIT Query Optimization
大多数时候,Mysql
也会对LIMIT row_count
语句(没有HAVING
)进行优化,大致总结如下:
- 当
LIMIT
只有小部分行时,Mysql
会选择用full table scan
,而不是使用索引 Mysql
扫描到LIMIT
限定的行数后就会停止扫描,如果有order by
就会停止排序,如果有distinct
也会停止扫描,此时,Mysql
可能只对表的大部分行进行了排序,所以会导致一个结果:带LIMIT
和不带LIMIT
的order by
的结果有几率不一致,该点下面会进行解释。Mysql
默认不会存储已经查询出来的结果,使用SQL_CALC_FOUND_ROWS
,这样子可以通过SELECT FOUND_ROWS()
来重复获取计算出来的结果。- 如果需要使用临时表,
Mysql
也会利用row_count
来计算所需要的空间。 如果使用了
LIMIT
,那么优化器也有可能避免使用filesort
,而是使用内存方式进行排序。
关于为什么带LIMIT
和不带LIMIT
可能结果不一样的原因:
当order by
的列有多个重复列的时候,如果带LIMIT
,Mysql
会进行部分排序,如果部分排序后发现数目已经满足LIMIT
的row_count
,那么就会停止排序,并将结果直接返回,而这个时候,有些数据还没有得到排序,所以这就导致了全排序(不带LIMIT
)和带LIMIT
的结果不一致,主要体现在其他列上面,来看下面的例子:
order by
的是category
列,表的数据如下:
mysql> SELECT * FROM ratings ORDER BY category;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 3 | 2 | 3.7 |
| 4 | 2 | 3.5 |
| 6 | 2 | 3.5 |
| 2 | 3 | 5.0 |
| 7 | 3 | 2.7 |
+----+----------+--------+
限制LIMIT 5
的结果可能为:
mysql> SELECT * FROM ratings ORDER BY category LIMIT 5;
+----+----------+--------+
| id | category | rating |
+----+----------+--------+
| 1 | 1 | 4.5 |
| 5 | 1 | 3.2 |
| 4 | 2 | 3.5 |
| 3 | 2 | 3.7 |
| 6 | 2 | 3.5 |
+----+----------+--------+
注意结果的第三行和第四行,和初始是不一样的,因为此时Mysql
可能只进行了部分排序,所以有几率出现这样的结果。Mysql
在实现排序的时候,只会保证order by
列的顺序,并不会保证其他列的顺序。
4 Function Call Optimization
在Mysql里面,Function
被分为两种:确定性函数和非确定性函数。
确定性函数:给定一个值,多次调用会确定性的返回另外一个值
非确定性函数:给定一个值,多次调用可能返回不同的值,比如:RAND(), UUID()
假设有下面的表:
CREATE TABLE t (id INT NOT NULL PRIMARY KEY, col_a VARCHAR(100));
对于下面的两种查询:
SELECT * FROM t WHERE id = POW(1,2);
SELECT * FROM t WHERE id = FLOOR(1 + RAND() * 49);
解释如下:
对于第一条语句:由于POW
产生一个固定的结果,所以Mysql会将其视为一个常量进行优化,有可能使用索引查找来快速找到对应记录。
对于第二条语句:由于RAND
会产生不同的结果,所以Mysql会对表t的每一行进行where
判断,相应的,就会进行全表扫描,因为需要RAND
来产生不同的结果。
综上,如果贸然使用非确定性的函数,对Mysql性能可能会产生隐性的不良影响,可能带来的影响有下面几种情况:
- 非确定性函数由于无法产生固定的结果,所以优化器就没办法对其优化,比如:如果是常量,可以使用
index lookup
,但是由于非确定性函数的存在,就只能用table scan
的方式了。 InnoDB
中,非确定性函数可能会导致锁由单行锁升级为range-key lock
。- 在复制操作中,
update
中有非确定性函数可能是不安全的。
如果不得不用确定性函数,可以使用下面的方式进行优化:
将
RAND
的结果首先赋值给一个常量,然后查询语句中直接使用该常量,这样,Mysql就会把where
语句后面的值视为常量来进行优化,比如此时可以使用index lookup
。SET @keyval = FLOOR(1 + RAND() * 49); UPDATE t SET col_a = some_expr WHERE id = @keyval;
将非确定性函数的值放在
derived table
里面,然后在where
语句里面直接使用derived table
里面的值,Mysql也可以使用相应的优化措施。UPDATE /*+ NO_MERGE(dt) */ t, (SELECT FLOOR(1 + RAND() * 49) AS r) AS dt SET col_a = some_expr WHERE id = dt.r;
有的时候,如果可以确定部分条件,那么用
and
连接起来非确定性函数,这样子可以导致非确定性函数的执行次数大大减少,比如下面的语句。SELECT * FROM t WHERE partial_key=5 AND some_column=RAND();
5 Avoiding Full Table Scans
在EXPLAIN
的输出结果里面,如果column
列显示为ALL
,那么说明Mysql
本次在进行全表扫描,为了避免全表扫描,而是让Mysql
使用索引,可用下面的方式:
使用
ANALYZE TABLE tbl_name
来更新表索引的分布性。使用
FORCE INDEX
命令告诉Mysql table scan
的效率要远低于使用索引。SELECT * FROM t1, t2 FORCE INDEX (index_for_column)WHERE t1.col_name=t2.col_name;
在启动Mysql的时候,
mysqld
命令加上--max-seeks-for-key=1000
或者说使用SET max_seeks_for_key=1000
, 该值设置的越低,那么Mysql就更倾向于使用索引。
转载于:https://www.cnblogs.com/seancheer/p/11278452.html
Mysql优化(出自官方文档) - 第五篇相关推荐
- Unity 优化翻译官方文档(二) ------ 平台特定覆盖的纹理压缩格式
官方文档 : https://docs.unity3d.com/Manual/class-TextureImporterOverride.html 虽然Unity支持许多常见的图像格式作为导入纹理的源 ...
- Axon Framework官方文档(五)
5.Command Model 在基于CQRS的应用程序中,一个领域模型(由Eric Evans和Martin Fowler提出的概念)可以是一种非常强大的机制,它可以利用状态更改的验证和执行所涉及的 ...
- 看懂mysql执行计划--官方文档
原文地址:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html 9.8.2 EXPLAIN Output Format The EXP ...
- Unity优化翻译官方文档(六) ------ CPU Usage Profiler
官网地址 : https://docs.unity3d.com/Manual/ProfilerCPU.html CPU使用分析器显示在您的游戏中花费的时间.当它被选中时,下窗格将显示所选帧的分层时间数 ...
- storm mysql trident_Apache Storm 官方文档 —— Trident 教程
Trident 是 Storm 的一种高度抽象的实时计算模型,它可以将高吞吐量(每秒百万级)数据输入.有状态的流式处理与低延时的分布式查询无缝结合起来.如果你了解 Pig 或者 Cascading 这 ...
- Nginx官方文档(十五)【HTTP之ngx_http_dav_module|ngx_http_empty_gif_module|ngx_http_f4f_module】
ngx_http_dav_module 示例配置 指令 dav_access dav_methods create_full_put_path min_delete_depth ngx_http_da ...
- Gstreamer离线版官方文档(十五)
1.GStreamer是什么? 众所周知,Microsoft's Windows和Apple's MacOS对多媒体设备.多媒体创作.播放和实时处理等方面都有很好的支持,而Linux对多媒体应用一直略 ...
- Unity 优化翻译官方文档(三) ------ Animation Clips
动画剪辑是Unity动画中最小的组成部分.它们代表了一个孤立的运动,如RunLeft.跳转或爬行,并且可以以各种方式进行操作和组合,以产生生动的最终结果(参见动画状态机.动画控制器控制器或混合树).您 ...
- [WebApp开发]基础教程-Google官方文档-第四篇
文档内容 在Android Browser中使用控制台API 在WebView中使用控制台API 参考 调试 如果你是在为Android开发web应用,那么,你可以使用控制台(console)的Jav ...
- 基于vue的微信小程序开发5分钟上手教程(官方文档转)
使用手册 mpvue 继承自 Vue.js,其技术规范和语法特点与 Vue.js 保持一致. 注:其实就是官方文档,只是习惯看博文学习才直接copy过来的,详见官方文档 本文档适用于有一定 Vue.j ...
最新文章
- c语言宏嵌套和展开规则
- FPGA和DSP间基于SRIO的高速通信系统设计
- 英雄联盟离线更新方法
- 利用TinyXML读取VOC2012数据集的XML标注文件裁剪出所有人体目标保存为文件
- SAP固定资产减值准备的处理方法
- spring bean依赖_Spring @Configuration并将bean依赖项作为方法参数注入
- sklearn-数据预处理scale
- 饥荒联机云服务器_GAMETECH腾讯云游戏行业技术沙龙成都站圆满落幕
- 1、mysql创建用户和授权总结
- UltraWebGrid两种显示样式
- 好用的局域网共享工具有哪些?win10系统如何设置?
- python 大智慧股池_大智慧竞价股池
- Julia Pro国内下载地址
- java语言判断101到200之间素数
- 汽车行业营销案例(共13份)
- android 外接扫码枪_Android 扫码枪以及焦点的处理
- 、用ecshop整合淘宝客api改造用于淘宝客程序
- EMC-电磁兼容-共模干扰与差模干扰
- 在线的图片颗粒化效果实现
- RK3568 外接 PCF8563 RTC
热门文章
- Android头部悬浮ListView第二种实现方式
- 微信小程序开发--【Hello World 及代码结构】(二)
- oracle的update加并发,关于update操作并发问题
- solr 配置多个entity_solr建索引优化
- C语言程序实验01,广西科技大学理学院《C语言程序设计与算法语言》实验01: 熟悉开发环境.pdf...
- java 环境变量 ln s_java的环境变量
- java软件测试方法有哪些方法有哪些方法_软件测试方法和软件测试规则
- 计算机信息管理自荐信个人简历,计算机信息专业英文自荐信
- 会java需要多久能学会python_学好Python,c++ 和Java要多久?
- vue.js简单登录界面访问mysql_Vuejs实战项目:登陆页面