一文掌握mysql数据库常见的优化手段、步骤,值得收藏
qiyuwang 2024-10-08 10:22 11 浏览 0 评论
概述
优化SQL,是DBA常见的工作之一。如何高效、快速地优化一条语句,是每个DBA经常要面对的一个问题。在日常的优化工作中,我发现有很多操作是在优化过程中必不可少的步骤。然而这些步骤重复性的执行,又会耗费DBA很多精力。
今天抽空总结下mysql数据库常见的一些优化步骤,仅供参考。
执行计划 — EXPLAIN命令
执行计划是语句优化的主要切入点,通过执行计划的判读了解语句的执行过程。在执行计划生成方面,MySQL与Oracle明显不同,它不会缓存执行计划,每次都执行“硬解析”。
1、基本用法
EXPLAIN QUERY
当在一个Select语句前使用关键字EXPLAIN时,MySQL会解释了即将如何运行该Select语句,它显示了表如何连接、连接的顺序等信息。
EXPLAIN EXTENDED QUERY
当使用EXTENDED关键字时,EXPLAIN产生附加信息,可以用SHOW WARNINGS浏览。该信息显示优化器限定SELECT语句中的表和列名,重写并且执行优化规则后SELECT语句是什么样子,并且还可能包括优化过程的其它注解。
EXPLAIN PARTITIONS QUERY
显示的是查询要访问的数据分片——如果有分片的话。它只能在MySQL5.1及更新的版本里使用。
EXPLAIN FORMAT=JSON (5.6新特性)
另一个格式显示执行计划。可以看到诸如表间关联方式等信息。
2、输出字段
下面说明一下EXPLAIN输出的字段含义:
id
MySQL选定的执行计划中查询的序列号。如果语句里没有子查询等情况,那么整个输出里就只有一个SELECT,这样一来每一行在这个列上都会显示一个1。如果语句中使用了子查询、集合操作、临时表等情况,会给ID列带来很大的复杂性。
select_type
语句所使用的查询类型。是简单SELECT还是复杂SELECT(如果是后者,显示它属于哪一种复杂类型)。常用有以下几种标记类型。
- DEPENDENT SUBQUERY
子查询内层的第一个SELECT,依赖于外部查询的结果集。
- DEPENDENT UNION
子查询中的UNION,且为UNION中从第二个SELECT开始的后面所有SELECT,同样依赖于外部查询的结果集。
- PRIMARY
子查询中的最外层查询,注意并不是主键查询。
- SIMPLE
除子查询或UNION之外的其他查询。
- SUBQUERY
子查询内层查询的第一个SELECT,结果不依赖于外部查询结果集。
- UNCACHEABLE SUBQUERY
结果集无法缓存的子查询。
- UNION
UNION语句中的第二个SELECT开始后面的所有SELECT,第一个SELECT为PRIMARY。
- UNION RESULT
UNION中的合并结果。从UNION临时表获取结果的SELECT。
- DERIVED
衍生表查询(FROM子句中的子查询)。MySQL会递归执行这些子查询,把结果放在临时表里。在内部,服务器就把当做一个"衍生表"那样来引用,因为临时表就是源自子查询。
table
这一步所访问的数据库中表的名称或者SQL语句指定的一个别名表。这个值可能是表名、表的别名或者一个为查询产生的临时表的标识符,如派生表、子查询或集合。
type
表的访问方式。以下列出了各种不同类型的表连接,依次是从最好的到最差的。
- system
系统表,表只有一行记录。这是const表连接类型的一个特例。
- const
读常量,最多只有一行匹配的记录。由于只有一行记录,优化程序里该行记录的字段值可以被当作是一个恒定值。const用于在和PRIMARY KEY或UNIQUE索引中有固定值比较的情形。
- eq_ref
最多只会有一条匹配结果,一般是通过主键或唯一键索引来访问。从该表中会有一行记录被读取出来以和从前一个表中读取出来的记录做联合。与const类型不同的是,这是最好的连接类型。它用在索引所有部分都用于做连接并且这个索引是一个PRIMARY KEY或UNIQUE类型。eq_ref可以用于在进行"="做比较时检索字段。比较的值可以是固定值或者是表达式,表达示中可以使用表里的字段,它们在读表之前已经准备好了。
- ref
JOIN语句中驱动表索引引用的查询。该表中所有符合检索值的记录都会被取出来和从上一个表中取出来的记录作联合。ref用于连接程序使用键的最左前缀或者是该键不是PRIMARY KEY或UNIQUE索引(换句话说,就是连接程序无法根据键值只取得一条记录)的情况。当根据键值只查询到少数几条匹配的记录时,这就是一个不错的连接类型。ref还可以用于检索字段使用"="操作符来比较的时候。
- ref_or_null
与ref的唯一区别就是在使用索引引用的查询之外再增加一个空值的查询。这种连接类型类似ref,不同的是MySQL会在检索的时候额外的搜索包含NULL值的记录。这种连接类型的优化是从MySQL 4.1.1开始的,它经常用于子查询。
- index_merge
查询中同时使用两个(或更多)索引,然后对索引结果进行合并(merge),再读取表数据。这种连接类型意味着使用了Index Merge优化方法。
- unique_subquery
子查询中的返回结果字段组合是主键或唯一约束。
- index_subquery
子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或唯一索引。这种连接类型类似unique_subquery。它用子查询来代替IN,不过它用于在子查询中没有唯一索引的情况下。
- range
索引范围扫描。只有在给定范围的记录才会被取出来,利用索引来取得一条记录。
- index
全索引扫描。连接类型跟ALL一样,不同的是它只扫描索引树。它通常会比ALL快点,因为索引文件通常比数据文件小。MySQL在查询的字段知识单独的索引的一部分的情况下使用这种连接类型。
- fulltext
全文索引扫描。
- all
全表扫描。
possible_keys
该字段是指MySQL在搜索表记录时可能使用哪个索引。如果没有任何索引可以使用,就会显示为null。
key
查询优化器从possible_keys中所选择使用的索引。key字段显示了MySQL实际上要用的索引。当没有任何索引被用到的时候,这个字段的值就是NULL。
key_len
被选中使用索引的索引键长度。key_len字段显示了MySQL使用索引的长度。当key字段的值为NULL时,索引的长度就是NULL。
ref
列出是通过常量,还是某个表的某个字段来过滤的。ref字段显示了哪些字段或者常量被用来和key配合从表中查询记录出来。
rows
该字段显示了查询优化器通过系统收集的统计信息估算出来的结果集记录条数。
Extra
该字段显示了查询中MySQL的附加信息。
filtered
这个列式在MySQL5.1里新加进去的,当使用EXPLAIN EXTENDED时才会出现。它显示的是针对表里符合某个条件(WHERE子句或联接条件)的记录数的百分比所作的一个悲观估算。
3、SQL改写
EXPLAIN除了可以显示执行计划外,还可以显示SQL改写。所谓SQL改写,是指MySQL在对SQL语句进行优化前,会基于一些原则进行语句的改写,以方便后面的优化器进行优化生成更优的执行计划。该功能是通过EXPLAIN EXTENDED+SHOW WARNINGS配合使用。
简单做个实验:
从上面示例中,可看到原有语句中的IN子查询被改写成为表间关联的方式。
统计信息
查看统计信息也是优化语句中必不可少的一步。通过统计信息可以快速了解对象的存储特征如何。下面说明主要的两类统计信息——表、索引。
1、表统计信息 — SHOW TABLE STATUS
说明如下:
- Name:表名
- Engine:表的存储引擎类型(ISAM、MyISAM或InnoDB)
- Row_format:行存储格式(Fixed-固定的、Dynamic-动态的或Compressed-压缩的)
- Rows:行数量。在某些存储引擎中,例如MyISAM和ISAM他们存储了精确的记录数。不过其他存储引擎中,它可能只是近似值。
- Avg_row_length:平均行长度。
- Data_length:数据文件的长度。
- Max_data_length:数据文件的最大长度。
- Index_length:索引文件的长度。
- Data_free:已分配但未使用了字节数。
- Auto_increment:下一个autoincrement(自动加1)值。
- Create_time:表被创造的时间。
- Update_time:数据文件最后更新的时间。
- Check_time:最后对表运行一个检查的时间。执行mysqlcheck命令后更新,仅对MyISAM有效。
- Create_options:额外留给CREATE TABLE的选项。
- Comment:当创造表时,使用的注释(或为什么MySQL不能存取表信息的一些信息)。
- Version:数据表的'.frm'文件版本号。
- Collation:表的字符集和校正字符集。
- Checksum:实时的校验和值(如果有的话)。
索引统计信息 — SHOW INDEX
说明如下:
- Table:表名。
- Non_unique:0,如果索引不能包含重复。
- Key_name:索引名
- Seq_in_index:索引中的列顺序号,从1开始。
- Column_name:列名。
- Collation:列怎样在索引中被排序。在MySQL中,这可以有值A(升序)或NULL(不排序)。
- Cardinality:索引中唯一值的数量。
- Sub_part:如果列只是部分被索引,索引字符的数量。当整个字段都做索引了,那么它的值是NULL。
- Packed:表示键值是如何压缩的,NULL表示没有压缩。
- Null:当字段包括NULL的记录是YES,它的值为,反之则是''。
- Index_type:使用了哪种索引算法(有BTREE、FULLTEXT、HASH、RTREE)。
- Comment:备注。
- 系统参数:系统参数也会影响语句的执行效率。查看系统参数,可使用SHOW VARIABLES命令。
优化器开关
在MySQL中,还有一些参数是可以用来控制优化器行为的。
1、参数说明
optimizer_search_depth
这个参数控制优化器在穷举执行计划时的限度。如果查询长时间处于"statistics"状态,可以考虑调低此参数。
optimizer_prune_level
默认是打开的,这让优化器会根据需要扫描的行数来决定是否跳过某些执行计划。
optimizer_switch
这个变量包含了一些开启/关闭优化器特性的标志位。
2、实验--干预优化器行为(ICP特性)
默认情况下,ICP特性是开启的。查看一下优化器行为。
基于二级索引的过滤查询,使用了ICP特性,从Extra中的”Using index condition”可见。如果通过优化器开关,干预优化器行为,又会如何呢?
set optimizer_switch="index_condition_pushdown=off";
从Extra可见,ICP特性已经禁用。
系统状态(SHOW STATUS)
MySQL中也内置了一些状态,通过这些状态变量也可反映出语句执行的一些情况,方便定位问题。手工执行的话,可以在执行语句的前后分别执行SHOW STATUS命令,查看状态的变化。
1、 状态变量
状态变量很多,这里只介绍几个常用的。
Sort_merge_passes
排序算法已经执行的合并的数量。如果这个变量值较大,应考虑增加sort_buffer_size系统变量的值。
Sort_range
在范围内执行的排序的数量。
Sort_rows
已经排序的行数。
Sort_scan
通过扫描表完成的排序的数量。
Handler_read_first
索引中第一条被读的次数。读取索引头的次数,如果这个值很高,说明全索引扫描很多。
Handler_read_key
根据键读一行的请求数。如果较高,说明查询和表的索引正确。
Handler_read_next
按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。
Handler_read_prev
按照键顺序读前一行的请求数。
Handler_read_rnd
根据固定位置读一行的请求数。如果执行大量查询并需要对结果进行排序该值较高。则可能使用了大量需要MySQL扫描整个表的查询或连接没有正确使用键。
Handler_read_rnd_next
在数据文件中读下一行的请求数。如果正进行大量的表扫描,该值较高。通常说明表索引不正确或写入的查询没有利用索引。
SQL性能分析器(Query Profiler)
MySQL的Query Profiler是一个使用非常方便的Query诊断分析工具,通过该工具可以获取一条Query在整个执行过程中多种资源的消耗情况,如CPU、IO、IPC、SWAP等,以及发生的PAGE FAULTS、CONTEXT SWITCHE等,同时还能得到该Query执行过程中的MySQL所调用的各个函数在源文件中的位置。
1、开启
mysql> select @@profiling; mysql> set profiling=1;
默认情况下profiling的值为0表示MySQL SQL Profiler处于OFF状态,开启SQL性能分析器后profiling的值为1。
2、执行SQL语句
mysql> select count(*) from t1;
3、获取概要信息
使用"show profile"命令获取当前系统中保存的多个Query的profile的概要信息。
mysql> show profiles;
4、针对单个Query获取详细的profile信息
在获取概要信息之后,就可以根据概要信息的Query_ID来获取某个Query的执行过程中详细的profile信息。
mysql> show profile for query 1; mysql> show profile cpu,block io for query 1;
其实还要慢查询部分也需要总结进来的,不过这块之前单独介绍了,所以这里就不放了,后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下!
相关推荐
- 在Word中分栏设置页码一页两个页码的技巧!
-
施老师:在正常情况下,Word文档中一页只会出现一个页码。但在某种情况下,比如说:用了分栏后,我们希望一页中出现两个页码,那应该如何实现呢?今天,就由宁双学好网施老师来为大家讲一下,利用域来实现一页两...
- 如何在关键时刻向上自荐(如何在关键时刻做出正确选择)
-
抓住机会,挺身而出有种时刻叫“关键时刻”,关键时刻,作为一个认为自己有能力的、训练有素的人,应该考虑挺身而出,甚至应该不考虑就挺身而出。...
- WPS Word:跨页的文档表格,快速调整为一页。#Excel
-
如何快速将跨页的文档表格调整为一页?需要根据两种情况分别处理。如果表格所有行的行高相同,调整为一页的方法有两种。第一种方法是将光标移动到表格内,然后将鼠标移动到表格右下角的方框处,按住鼠标左键向上拖动...
- word文档插入下一页分节符(word下一页分页符)
-
在word文档中,对文档页面进行分页是特别常见的操作,其中的下一页分节符也是用得比较多的,但是一些人不太清楚在哪里设置,也不知道它具体能实现的功能是什么。接下来看看如何在word文档中插入下一页分节符...
- word文档如何设置某一页纸张的方向
-
word文档页面方向有横向和纵向,纵向是默认的纸张方向,有时我们需要将页面设置为横向,或只设置其中某一页方向,应该怎么操作呢?一起来看看下面的详细介绍第一步:...
- word怎么单独设置一页为横向(word2019怎样设置单独一页为横向)
-
word里面其中一页可以改为横向的吗?经过实际操作发现是完全可以的。...
- Word如何设置分栏,如何一页内容同时显示一栏和两栏
-
我们使用Word文档,有时需要用到两栏的排版,甚至一页内容同时包含一栏和两栏的排版,这种格式怎么设置呢?具体步骤如下:首先是两栏排版的设置,直接点击Word文件上方工具栏【布局】,选择【分栏】下面的【...
- Word怎么分页?这三个方法可以帮到你
-
我们不仅可以利用Word编辑文档,还可以编辑文集呢。但是有时候会出现两个部分的文章长短不一,我们需要对文档进行分页处理。这样可以方便我们对文档进行其他操作。那么Word怎么分页呢?大家可以采用下面这...
- Word内容稍超一页,如何优化至单页打印?
-
如何将两页纸的内容,缩到一页打印呢?有时候一页纸多一点内容,我们完全可以缩一下,放到一页来打印。...
- [word] word 表格如何跨行显示表头、标题
-
word表格如何跨行显示表头、标题在Word中的表格如果过长的话,会跨行显示在另一页,如果想要在其它页面上也显示表头,更直观的查看数据。难道要一个个复制表头吗?当然不是,教你简单的方法操作设置Wo...
- Word表格跨页如何续上表?(word如何让表格跨页不断掉)
-
长文档的表格跨页时,你会发现页末空白太多了,这时要怎么调整?选中整张表格,右击【表格属性】,点击【行】选项,之后勾选【允许跨页断行】,点击确定即可解决空白问题。...
- Word怎么连续自动生成页码,操作步骤来了!
-
Word怎么连续自动生成页码,操作步骤来了!...
- word文档怎么把两页合并成一页内容?教你4种方法
-
word怎么把两页合并成一页?word怎么把两页合并成一页?用四种方法演示一下。·方法一:把这一个文档合并成一页,按ctrl加a全选文档,然后右键点击段落,弹出的界面行距改成固定值,磅值可以改小一点,...
- 如何将Word中的一页的纸张方向设置为横向?这里提供详细步骤
-
默认情况下,MicrosoftWord将页面定向为纵向视图。虽然这在大多数情况下都很好,但你可能拥有在横向视图中看起来更好的页面或页面组。以下是实现这一目标的两种方法。无论使用哪种方法,请注意,如果...
- Word横竖混排你会玩吗?(word横排竖排混合)
-
我们在用Word排版的时候,一般都是竖版格式,但偶尔会需要到一些特殊的版式要求,比如文档中插入的一个表格,横向的内容比较多,这时就需要用到横版,否则表格显示不全。这种横竖版混排的要求,在Word20...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- navicat无法连接mysql服务器 (65)
- 下横线怎么打 (71)
- flash插件怎么安装 (60)
- lol体验服怎么进 (66)
- ae插件怎么安装 (62)
- yum卸载 (75)
- .key文件 (63)
- cad一打开就致命错误是怎么回事 (61)
- rpm文件怎么安装 (66)
- linux取消挂载 (81)
- ie代理配置错误 (61)
- ajax error (67)
- centos7 重启网络 (67)
- centos6下载 (58)
- mysql 外网访问权限 (69)
- centos查看内核版本 (61)
- ps错误16 (66)
- nodejs读取json文件 (64)
- centos7 1810 (59)
- 加载com加载项时运行错误 (67)
- php打乱数组顺序 (68)
- cad安装失败怎么解决 (58)
- 因文件头错误而不能打开怎么解决 (68)
- js判断字符串为空 (62)
- centos查看端口 (64)