mysql查询优化之一:mysql查询优化常用方式

一、为什么查询速度会慢? 

  一个查询的生命周期大致可以按照顺序来看:从客户端,到服务器,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。其中在“执行”阶段包含了大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组。 
查询速度慢的原因在于:某些不必要的额外操作,某些操作被额外地重复很多次,某些操作执行得太慢。 
优化查询的目的就是减少和消除这些操作所花费的时间。

二、慢查询基础:优化数据访问

查询性能低下最基本的原因是访问的数据太多。所以对于低效的查询可以从下面两个方面来分析: 
1.确认应用程序是否在检索大量超过需要的数据。 
2.确认MySQL服务器层是否在分析大量超过需要的数据行。 
2.1、是否向数据库请求了不需要的数据

请求多余的数据会给MySQL服务器带来额外的负担,并增加网络开销,另外也会消耗应用服务器的CPU内存和资源。低效的查询表现在如下方面: 

1、查询不需要的记录:例如在新闻网站中取出100条记录,但是只是在页面上显示10条。实际上MySQL会查询出全部的结果,客户端的应用程序会接收全部的结果集数据,然后抛弃其中大部分数据。最简单有效的解决方法就是在这样的查询后面加上LIMIT。

2、多表关联时返回全部列,例如:

3、总是取出全部的列:每次看到SELECT *的时候都需要怀疑是不是真的需要返回全部的列?取出全部列,会主优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的IO、内存和CPU的消耗。如果应用程序使用了某种缓存机制,或者有其他考虑,获取超过需要的数据也可能有其好处,但不要忘记这样做的代价是什么。获取并缓存所有的列的查询,相比多个独立的只获取部分列的查询可能就更有好处。

4、重复查询相同的数据:不要不断地重复执行相同的查询,然后每次都返回完全相同的数据。当初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能显然更好。

注:在查询语句中慎用select * 语句,我们对数据库的数据应该只取所需。 
2.2、mysql是否在扫描额外的记录 
在确定查询只返回需要的数据之后,那么查询为了返回结果是否扫描了过多的数据,有以下三个指标衡量查询的开销:

  • 响应时间
  • 扫描的行数
  • 返回的行数

通过查询慢日志可以找到这三个指标的记录。

响应时间

响应时间是两个部分之和:服务时间和排队时间,一般常见和重要的等待是IO和锁等待。

扫描的行数和返回的行数

分析查询时,查看该查询扫描的行数是非常有帮助的。一定程度上能够说明该查询找到需要的数据的效率高不高。理想的情况下扫描的行数和返回的行数应该是相同的。当然这只是理想情况。一般来说扫描的行数对返回的行数的比率通常很小,一般在1:1到10:1之间。

扫描的行数和访问类型

MySQL有好几种访问方式可以查找并返回一行结果。有些访问方式可能需要扫描很多行才能返回一行结果,也有些访问方式可能无须扫描就能返回结果。

在EXPLAIN语句的TYPE列返回了访问类型。如果查询没有办法找到合适的访问类型,那么解决的最好办法通常就是增加一个合适的索引。索引让MySQL以最高效、扫描行最少的方式找到需要的记录。

一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次为:

1、在索引中使用WHERE条件来过滤不匹配的记录。这是在存储引擎层完成的。

2、使用索引覆盖扫描(在extra列中出现了using index)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层完成的,但无须回表查询记录。

3、从数据表中返回数据,然后过滤不满足条件的记录(在extra列中出现using where)。这在MySQL服务器层完成,MySQL需要先从数据表读出记录然后过滤。

 

三、重构查询的方式

选择一个复杂的查询还是多个简单的查询? 
书中作者的观点:在MySQL内部每秒能够扫描内存中上百行的数据,相比之下MySQL响应数据给客服端就慢的多了。其他条件都相同的时候,使用尽可能少的查询是更好的。但是并不否认将一个大的查询分解为多个小的查询。 
将查询分解的方法: 
3.1、切分查询:顾名思义,就是将一个大的查询切分为许多小的查询,每个小查询功能完全一样,返回一部分结果,我们只需重复执行小查询就行。(应用:在清除大量的数据时,如果一个大的语句可能一次性要耗费许多资源,阻塞其他查询,这时我们可以将其切分为多个小的查询,即每个查询只删除适量的查询,多次进行)

示例:删除历史数据的任务

DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH);

可以用以下类似的方法完成同样的工作:

rows_affected=0;
do {
rows_affected = do_query(
"DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH) LIMIT 10000"
)
} while rows_affected >0

一次删除一万行一般来说是一个比较高效而且对服务器影响也最小的做法。需要注意,如果删除后暂停一会儿,再执行下一次,可以大大降低服务器的影响,还可以大大减少删除时锁的持有时间。

 
3.2、分解关联查询 
可将单条的多表关联查询分解为多条查询,对每一个表进行一次单表查询,然后将结果在应用程序中进行关联。(将在数据库中做的关联查询,转移到了应用层) 

示例:

优点: 
a.让缓存的效率更高。对单表查询的结果,应用程序可以很方便的缓存,分解语句之后,我们可以高效的利用缓存来进行查询。 
b.将查询分解之后,执行单个查询可以减少锁的竞争。 
c.在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展。 
d.查询本身的效率也会得到提升。按照ID顺序查询比随机的关联要更加的高效。(使用in()的方式代替关联查询的join…on…) 
e.减少冗余记录的查询。在应用层做关联查询,对于某条记录应用只需要查询一次,而在数据库中做关联查询,则可能需要重复的访问某一部分的数据。

四、查询执行的基础

MySQL是如何优化和执行查询的? 

 

 
1.客户端发送一条查询给服务器; 
2.服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段; 
3.服务器进行SQL解析、预处理、在由查询优化器生成对应的执行计划; 
4.MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。 
5.将结果返回给客服端,同时也会放入查询缓存中。 


4.1、MySQL客户端/服务器通信协议 

MySQL客户端和服务器之间的通信协议是“半双工”的,这意味着在任何一个时刻,要么是由服务器向客户端发送数据,要么是由客户端向服务器发送数据,这两个动作不能同时进行。这种通信方式造成了许多限制。 
在多数连接MySQL的库函数(调用MySQL数据库的函数方法)默认一般是获得全部结果集并缓存到内存里。 
当然有时候这种全部缓存的方法并不好,一个很大的结果集在缓存时会占有大量的时间和内存。不使用缓存,从服务器中获取数据,然后直接处理,不过这样会加大服务器的压力,服务器只有在查询完成后才能释放资源。 

查询状态:可以使用SHOW FULL PROCESSLIST命令查看查询的执行状态。Sleep、Query、Locked、Analyzing and statistics、Copying to tmp table[on disk]、Sorting result、Sending data

详细见《mysql show processlist命令 详解

4.2、查询缓存(query cache) 

如果查询缓存打开,那么mysql会优先检查这个查询是否命中查询缓存中的数据。这是检查是通过一个对大小写敏感的哈希查找实现的。如果当前的查询恰好命中了查询缓存,那么在返回查询结果之前MySQL会检查一次用户权限。如果权限没有问题,MySQL会跳过执行阶段,直接从缓存中拿到结果并返回给客户端。 

详细见《MySQL查询缓存总结》

4.3、查询优化处理

查询生命周期的下一步是将一个SQL转换成一个执行计划,MySQL再依照这个执行计划和存储引擎进行交互。这包括多个子阶段:解析SQL、预处理、优化SQL执行计划。

1、语法解析器和预处理首先MySQL通过关键字将SQL语句进行解析,并生成一棵解析树。MySQL解析器将使用MySQL语法规则验证和解析查询。例如是否使用错误的关键字,或者使用关键字的顺序是否正确,引号是否能前后正确匹配等。

2、预处理器则根据一些MySQL规则进一步检查解析树是否合法,例如检查数据表和数据列是否存在,还会解析名字和别名看它们是否有歧义。

3、一下步预处理会验证权限。


查询优化器 

一条语句 可以有很多种执行方式,最后都返回相同的结果。优化器的作用就是找到最好的执行计划。MySQL使用基于成本的优化器,它将尝试预测一个查询使用某种执行计划时的成本,并选择其中成本最小的一个。成本的最小单位是随机读取一个4K的数据页的成本,并加入一些因子来估算某引动操作的代价。可以通过查询当前会话的Last_query_cost的值来得知MySQL计算的当前查询的成本。

这是根据一系列的统计信息计算得来的:每个表或者索引的页面个数、索引的基数(索引中不同值的数量)、索引和数据行的长度、索引分布情况。

当然很多原因会导致MySQL优化器选择错误的执行计划:例如统计信息不准确或执行计划中的成本估算不等同于实际执行的成本。

可通过查询当前会话的Last_query_cost的值来得知MySQL计算的当前查询的成本,如下:

上述语句预测了此count(*)操作大概需要做1.8个数据页的随机查找才能完成。 


MySQL能够处理的优化类型: 
1.重新定义关联表的顺序; 
2.将外连接转化为内连接; 
3.使用等价变化规则;可以合并和减少一些比较,还可以移除一些恒成立和恒不成立的判断。 
4.优化count()、min()和max();索引和列是否可为空通常可以帮助MySQL优化这类的表达式,如查找最小值,只需找到索引树最左边的第一条记录。 
5.预估并转化为常数表达式;当MySQL检测到一个表达式可以转化为常数时,就会一直把该表达式作为常数进行优化处理。 
6.覆盖索引扫描;当扫描的索引列包含所有查询中需要的使用的列时,MySQL就可以直接使用索引返回需要的数据。 
7.子查询优化; 
8.提前终止查询;如使用limit子句查找限制数量的数据。 
9.等值传播;如果两个列的值通过等式关联,那么MySQL能够将其中一个列的where条件传递到另一个列上。 
10.列表in()的比较;MySQL对in()列表进行优化,先对列表中的值进行排序,然后通过二分查找的方式来确定列表中的值是否满足条件。 

MySQL如何执行关联查询:MySQL对任何关联都执行嵌套循环关联操作,即MySQL先在一个表中循环取出单条数据,然后再嵌套循环到一个表中寻找匹配的行,依次下去直到找到的有匹配的行为止。然后根据各个表匹配的行,返回查询中需要的各个列。(嵌套循环关联)

 

执行计划:MySQL生成查询的一棵指令树,然后通过存储引擎执行完成这棵指令树并返回结果。最终的执行计划包含了重构查询的全部信息。如果对某个查询执行EXPLAIN EXTENDED,再执行SHOW WARNINGS,就可以看到重构出的查询。

MySQL的执行计划是一棵左侧深度优先的树。

不过,如果有超过n个表的关联,那么需要检查n的阶乘种关联顺序。我们称之为所有可能的执行计划的“搜索空间”。实际上,当需要关联的表超过optimizer_search_depth的限制的时候,就会选择“贪婪”搜索模式。


MySQL的排序优化: 

无论如何排序都是一个成本很高的操作,所以从性能角度考虑,应尽可能避免排序或者尽可能避免对大量数据进行排序。如果需要排序的数据量小于排序缓冲区,MySQL使用内存进行“快速排序”操作。如果内存不够排序,那么MySQL会先将数据分块,对每个独立的块使用“快速排序”进行排序,并将各个块的排序结果存放在磁盘上,然后将各个排序的块进行合并,最手返回排序结果。

MySQL有两种排序方法:

    两次传输排序(旧版),读取行指针和需要排序的字段,对其进行排序,然后再根据排序结果读取所需要的数据行。显然是两次传输,特别是读取排序后的数据时(第二次)大量随机I/O,所以两次传输成本高。
    单次传输排序(新版),一次读取出所有需要的或SQL查询指定的列,然后根据排序列,排序,直接返回排序后的结果。顺序I/O,缺点:如果列多,额外占用空间。

MySQL在进行文件排序时需要使用的临时存储空间可能会比想象的要大得多,因为MySQL在排序时,对每一个排序记录都会分配一个足够长的定长空间来存放。这个定长空间必须足够以容纳其中最长的字符串。

在关联查询的时候如果需要排序,MySQL会分两种情况来处理这样的文件排序。如果ORDER BY子句的所有列都来自关联的第一个表,那么MySQL在关联处理第一个表时就进行文件排序。如果是这样那么在MySQL的EXPLAIN结果中可以看到Extra字段会有Using filesort。除此之外的所有情况,MySQL都会将关联的结果存放在一个临时表中,然后在所有的关联都结束后,再进行文件排序。这种情况下Extra字段可以看到Using temporary;Using filesort。如果查询中有LIMIT的话,LIMIT也会在排序之后应用,所以即使需要返回较少的数据,临时表和需要排序的数据量仍然会非常大。

4.4、 查询执行引擎

相对于查询优化,查询执行简单些了,MySQL只根据执行计划输出的指令逐步执行。指令都是调用存储引擎的API来完成,一般称为 handler API,实际上,MySQL优化阶段为每个表都创建了一个 handler 实例,用 handler 实例获取表的相关信息(列名、索引统计信息等)。

存储引擎接口有着非常丰富的功能,但是底层接口却只有几十个,这些接口像搭积木一样能够完成查询的大部分操作。例如,有一个查询某个索引的第一行的接口,再有一个查询某个索引条件的下一条目的功能,有了这两个功能就可以完成全索引扫描操作。

 

4.5、 返回结果给客户端

查询执行的最后一个阶段就是将结果返回给客户端。即使查询不需要返回结果集给客户端,MySQL仍然会返回这个查询的一些信息,例如该查询影响到的行数。

MySQL将结果集返回客户端是一个增量、逐步返回的过程。一旦服务器处理完最后一个关联表,开始生成第一条结果时,MySQL就可以开始向客户端逐步返回结果集了。

这样处理有两个好处:服务端无须存储太多的结果,也就不会因为要返回太多结果而消耗太多内存。另外,这样的处理也让MySQL客户端第一时间获得返回的结果。

 

七、优化特定类型的查询

优化COUNT()查询 
count(*):统计行数,比统计一般的列值个数要快很多。 
简单的优化:通过修改条件语句,减少扫描的次数。(始终记住,计算count(*)是很快的,比计算所有带条件的统计都要快) 
使用近似值:即count()结果可以用一个优化器估算出来的值代替。 
优化关联查询 
1.确保ON或者USING子句中的列上有索引,一般索引建立在最后个关联表上的相应列上。 
2.确保任何时候的GROUP BY 和 ORDER BY 中的表达式只涉及到一个表上的列,这样MySQL才有可能使用索引来优化这个过程。 
优化子查询 
尽可能使用关联查询代替子查询。

转载于:https://www.cnblogs.com/duanxz/p/3682138.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音右上角一个小黄点是什么_抖音官方入驻视频号,释放了一个什么样的信号?...

专注视频号观察第 328 篇这几天&#xff0c;视频号生态新入驻了一个企业号&#xff0c;在圈里引起不少的轰动&#xff0c;因为这个号的名字叫做———抖音。这件事在圈里引发不少的轰动&#xff0c;很多人惊叹&#xff1a;“连抖音都来开视频号了&#xff0c;你还在等什么&…

Jenkins:部署JEE工件

随着持续集成和持续交付的出现 &#xff0c;我们的构建被分为不同的步骤&#xff0c;以创建部署管道。 这些步骤中的一些步骤可以是例如编译和运行快速测试&#xff0c;运行慢速测试&#xff0c;运行自动验收测试或发布应用程序等。 部署流程的最后一步意味着将我们的产品&…

seafile 部署_Seafile开启webdav及读写性能测试

为什么要在seafile搞webdavSeafile 一直是一款可靠的文件同步web应用&#xff0c;经过个人测试&#xff0c;同一台机器上&#xff0c;seafile在传输文件时的速度比nextcloud要快&#xff08;可能也与php的设置有关系&#xff09;&#xff0c;这是seafile的优势。但是&#xff0…

Python--校园网爬虫记

查成绩&#xff0c;算分数&#xff0c;每年的综合测评都是个固定的过程&#xff0c;作为软件开发者&#xff0c;这些过程当然可以交给代码去做&#xff0c;通过脚本进行网络请求获取数据&#xff0c;然后直接进行计算得到基础分直接填表就好了&#xff0c;查成绩再手动计算既容…

Spring–添加SpringMVC –第1部分

欢迎来到本教程的第四部分。 在这一部分中&#xff0c;我们将使用Spring MVC编写控制器和视图&#xff0c;并考虑我们的REST模型。 我们必须做的第一件事&#xff0c;就是根据目前的情况制作一个Web应用程序。 我们将web / WEB-INF文件夹添加到我们的项目根目录。 在WEB-INF内创…

access month函数用法_学会了这7个EXCEL日期函数技巧,老板再让你加班,你找我!...

日期函数&#xff0c;常用年月日&#xff0c;时分秒&#xff0c;星期&#xff0c;季度&#xff0c;求差值等&#xff0c;学会以下几个函数&#xff0c;老板再让你加班&#xff0c;你找我&#xff01;1、记录当前时间(不随系统时间变化)NOW()函数与数据有效性结合&#xff0c;记…

meta 的作用 搜集

Meta标签中的format-detection属性及含义 format-detection翻译成中文的意思是“格式检测”&#xff0c;顾名思义&#xff0c;它是用来检测html里的一些格式的&#xff0c;那关于meta的format-detection属性主要是有以下几个设置&#xff1a;<meta name"format-detecti…

ThinkPHP 3.2.x 集成极光推送指北

3.2版本已经过了维护生命周期&#xff0c;官方已经不再维护&#xff0c;请及时更新至5.0版本 —— ThinkPHP 官方仓库 以上&#xff0c;如果有条件&#xff0c;请关闭这个页面&#xff0c;然后升级至 ThinkPHP 5&#xff0c;如果由于各种各样的原因无法升级至 TP 5 &#xff0c…

Java多线程——不变性与安全发布

1、不变性 某个对象在被创建后其状态就不能被修改&#xff0c;那么这个对象就称为不可变对象&#xff0c;不可变对象一定是线程安全的。不可变对象很简单。他们只有一种状态&#xff0c;并且该状态由构造函数来控制。 当满足以下条件时&#xff0c;对象才是不可变的&#xff1a…

中tr不能显示字符_垃圾文本识别中基本操作指南和错误总结,第三部分

创建模型需要用到机器学习的库&#xff0c;所以我们先下载sklearn库sklearn库下载完成后再输入库文件&#xff0c;就可以完美运行。然后就是划分测试集和训练集&#xff0c;需要注意的是&#xff0c;在从数据处理函数中导入数据时&#xff0c;足足运行了有将近30多秒&#xff0…

(转载)20分钟读懂程序集

转自&#xff1a;http://www.cnblogs.com/damonlan/p/3221347.html 说到程序集&#xff0c;我刚开始对这个名词特别的郁闷&#xff01;~。然后 前些天花了些时间 好好读了一下&#xff0c;现在比较清晰了&#xff0c;把一些书上看到的 记下来&#xff0c;以飨读者。希望没浪费你…

大数据胸_喂母乳会导致胸下垂?!你被这个谣言骗了多少年?

很多人认为&#xff0c;给宝宝喂奶会导致胸下垂。有些爱美的妈妈&#xff0c;甚至在宝宝出生6个月后就着急断奶。那么&#xff0c;喂奶真的会导致胸下垂么&#xff1f;给大家讲两个真实的调查结果哈~2004年的一次针对496名新妈妈的调查结果显示&#xff0c;有75%的母乳喂养母亲…

自制ACL+DHCP实验(初版)

&#xff08;实验用gns模拟器&#xff09; ACL 实验拓扑&#xff1a; 实验要求&#xff1a; 1.1.1.1→3.3.3.3 不通 11.11.11.11→3.3.3.3 通 2.2.2.2→3.3.3.3 通 实验步骤&#xff1a; 步骤一&#xff1a;基本配置 R1&#xff1a; R1#conf t R1(config)#int lo0 R1(config-if…

pil 图像最大值_第97天:图像库 PIL(二)

上节我们讲了 Python 的图像处理库 PIL 的基本图像处理功能&#xff0c;打开了 PIL 的神秘面纱。这节我们接着讲 PIL 的 Image 模块的常用方法。Image 模块的方法convertImage.convert(modeNone, matrixNone, ditherNone, palette0, colors256)参数说明&#xff1a;mode&#x…

c#的委托用法delegate

转载于:https://www.cnblogs.com/douzujun/p/6555886.html

np读取csv文件_被 Pandas read_csv 坑了

-- 不怕前路坎坷&#xff0c;只怕从一开始就走错了方向Pandas 是python的一个数据分析包&#xff0c;纳入了大量库和一些标准的数据模型&#xff0c;提供了高效地操作大型数据集所需的工具。Pandas 就是为解决数据分析任务生的&#xff0c;无论是数据分析还是机器学习项目数据预…

铃木uy125摩托车机油_UY125 新瑞梦UM125发布 济南铃木于湖南株洲吹响国IV集结号...

​4月18日&#xff0c;济南铃木在湖南株洲天台开元酒店举行了2019年新品发布会&#xff0c;并于现场发布了两款极具终端战略意义的新款国IV车型&#xff0c;分别为定位“实用运动”的全新个性化踏板车型UY125&#xff0c;以及能够进一步巩固济南铃木在国IV入门级踏板车型领域绝…

js判断时间是早上还是下午_牛奶早上喝好,还是晚上喝好?没想到“最佳时间”是这个点,颠覆了!...

都说喝牛奶好&#xff0c;要多喝。可什么时间喝牛奶最好呢&#xff1f;是饭前、饭后还是睡前&#xff1f;又或者喝酒前&#xff1f;确实得好好说说。传言&#xff1a;空腹时身体比较缺能量&#xff0c;牛奶里的蛋白会去提供能量&#xff0c;不会去构成和修复组织(比如修复皮肤)…

Python TK编程第一部分 Hello Again

当你想写大一点的程序的时候&#xff0c;将你的代码封装到一个或者多个类里会是一个不错的办法。下面hello world这个例子来自Matt Conway的Tkinter Life Preserver. [python]view plain copy from Tkinter import * class App: def __init__(self, master): …

视网膜脱离oct报告图_刚刚,爱尔眼科发布关于艾芬医生诊疗过程的核查报告

刚刚&#xff0c;爱尔眼科医院集团发布关于艾芬女士诊疗过程的核查报告&#xff0c;内容如下&#xff1a;得悉艾芬女士对武汉爱尔眼科医院白内障诊疗存疑&#xff0c;爱尔眼科医院集团高度重视&#xff0c;第一时间成立了工作组奔赴武汉&#xff0c;对事件的诊疗全过程开展了核…