如何利用explain来分析sql语句,利用OPTIMIZER_TRACE对排序语句分析。
一.sql语句的优化
1.Sql语句的时间花在哪?
等待时间和执行时间
这两个时间并非孤立的,如果单条语句执行的快了对其他语句的锁定也就少了
分析如何降低执行时间。
2.Sql语句的执行时间,又花到哪了?
查找-> 沿着索引查找慢着可能全表扫描。
取出-> 查找行后把结果取出来。
如何查询快?
a) 查询的快—联合索引的顺序区分度,长度
b) 取的快,索引覆盖
c) 传输的少的行和列
切分查询:按数据拆成多次
如 : 插入10000行数据,每1000条为单位,插入
分解查询:按照逻辑把多表链接查询分成多个简单查询sql,
3.sql语句优化思路?
不查 —> 少查 –> 高效的查
不查,通过业务逻辑来计算
比如 论坛注册会员的数,我们可以根据前三个月统计每天注册量,用程序估算。
少量,尽可能精准数据,我们观察新闻网站,内容等一般一次性取列表10 –30条左右
必须查的尽量走在索引查询行
取时,取尽量少的列。比如 select * from tableA 取出所有列,不建议
如果定量分析查的多少行和是否沿着索引查?
二.使用explain来分析
id:代表select语句的编号,如果是链接查询表之间是平等关系select编号是从1开始,如果某select中有子查询则编号递增。
注意:id列数字越大越先执行,如果说数字一样大,那么就从上往下依次执行。
Select_type:查询类型
| select_type Value | JSON Name | Meaning |
|---|---|---|
| SIMPLE | None | Simple SELECT (not using UNION or subqueries) |
| PRIMARY | None | Outermost SELECT |
| UNION | None | Second or later SELECT statement in a UNION |
| DEPENDENT UNION | dependent (true) | Second or later SELECT statement in a UNION, dependent on outer query |
| UNION RESULT | union_result | Result of a UNION. |
| SUBQUERY | None | First SELECT in subquery |
| DEPENDENT SUBQUERY | dependent (true) | First SELECT in subquery, dependent on outer query |
| DERIVED | None | Derived table SELECT (subquery in FROM clause) |
| MATERIALIZED | materialized_from_subquery | Materialized subquery |
| UNCACHEABLE SUBQUERY | cacheable (false) | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query |
| UNCACHEABLE UNION | cacheable (false) | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
各项内容含义说明:
- A:simple:表示不需要union操作或者不包含子查询的简单select查询。有连接查询时,外层的查询为simple,且只有一个。
- B:primary:一个需要union操作或者含有子查询的select,位于最外层的单位查询的select_type即为primary。且只有一个。
- C:union:union连接的select查询,除了第一个表外,第二个及以后的表select_type都是union。
- D:dependent union:与union一样,出现在union 或union all语句中,但是这个查询要受到外部查询的影响
- E:union result:包含union的结果集,在union和union all语句中,因为它不需要参与查询,所以id字段为null
- F:subquery:除了from字句中包含的子查询外,其他地方出现的子查询都可能是subquery
- G:dependent subquery:与dependent union类似,表示这个subquery的查询要受到外部表查询的影响
- H:derived:from字句中出现的子查询。
- I:materialized:被物化的子查询
- J:UNCACHEABLE SUBQUERY:对于外层的主表,子查询不可被物化,每次都需要计算(耗时操作)
- K:UNCACHEABLE UNION:UNION操作中,内层的不可被物化的子查询(类似于UNCACHEABLE SUBQUERY)
|
|
Table:查询针对的表
有可能 实际表名或者表别名 (from A2 as a2)
Derived 如from 型子查询
Null 直接计算的结果不走表
Possible_key : 可能用到的索引
注意:可能用几个索引最终只能用一个
Key :最终用的索引
Key_len : 使用索引最大长度
注:有可能possible_keys为Null 而key不为NULL这种情况
Possible_keys分析的是索引用于查找的过程。
而最终的key可能是被用于查找,排序或索引覆盖
Type列: 是指查询的方式,非常重要是分析查数据的过程的重要依据
可能的值如下:
依次从好到差:system,const,eq_ref,ref,fulltext,ref_or_null,index_merge,unique_subquery,index_subquery,range,index,ALL,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引
- A:system:表中只有一行数据或者是空表,且只能用于myisam和memory表。如果是Innodb引擎表,type列在这个情况通常都是all或者index
- B:const:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描
- C:eq_ref:出现在要连接过个表的查询计划中,驱动表只返回一行数据,且这行数据是第二个表的主键或者唯一索引,且必须为not null,唯一索引和主键是多列时,只有所有的列都用作比较时才会出现eq_ref
- D:ref:不像eq_ref那样要求连接顺序,也没有主键和唯一索引的要求,只要使用相等条件检索时就可能出现,常见与辅助索引的等值查找。或者多列主键、唯一索引中,使用第一个列之外的列作为等值查找也会出现,总之,返回数据不唯一的等值查找就可能出现。
- E:fulltext:全文索引检索,要注意,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
- F:ref_or_null:与ref方法类似,只是增加了null值的比较。实际用的不多。
例如:
SELECT * FROM ref_table
WHERE key_column=expr OR key_column IS NULL; - G:index_merge:表示查询使用了两个以上的索引,最后取交集或者并集,常见and ,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取所个索引,性能可能大部分时间都不如range
- H:unique_subquery:用于where中的in形式子查询,子查询返回不重复值唯一值
- I:index_subquery:用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。
- J:range:索引范围扫描,常见于使用 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, IN()或者like等运算符的查询中。
- K:index:索引全表扫描,把索引从头到尾扫一遍,常见于使用索引列就可以处理不需要读取数据文件的查询、可以使用索引排序或者分组的查询。按照官方文档的说法:
- all :意味着从标的第一行往后逐行扫描,运气不好扫描到最后一行。
通俗说:all扫描所有的数据行,相当于data_all index扫描所有索引节点相当于index_all
Range:意思是查询时能根据索引做范围扫描
1索引覆盖的查询情况下,能利用上索引数据,但利用不上索引查询必须全索引扫描
以上说的是索引扫描的两种情况,一种是查询使用了覆盖索引,那么它只需要扫描索引就可以获得数据,这个效率要比全表扫描要快,因为索引通常比数据表小,而且还能避免二次查询。在extra中显示Using index,反之,如果在索引上进行全表扫描,没有Using index的提示。
Ref:意思指通过索引列可以直接引用到某些数据行
Eq_ref 是指通过索引列直接引用某1行数据
常见于链接查询中
Const,system,null 这三个分别指查询优化到常量级别甚至不需要查询时间
一般按照主键查询易出现const,system
或者直接查询某个表达式不经过表时,出现null
Rows:预计要扫描多少行
Extra:
|
|
大概的意思就是说,如果你想要优化你的查询,那就要注意extra辅助信息中的using filesort和using temporary,这两项非常消耗性能,需要注意。
- A:distinct:在select部分使用了distinc关键字。
- B:no tables used:不带from字句的查询或者From dual查询。
- C:使用not in()形式子查询或not exists运算符的连接查询,这种叫做反连接。即,一般连接查询是先查询内表,再查询外表,反连接就是先查询外表,再查询内表。
- D:using filesort:排序时无法使用到索引时,就会出现这个。常见于order by和group by语句中。
- E:using index:查询时不需要回表查询,直接通过索引就可以获取查询的数据。
- F:using join buffer(block nested loop),using join buffer(batched key accss):5.6.x之后的版本优化关联查询的BNL,BKA特性。主要是减少内表的循环数量以及比较顺序地扫描查询。
- G:using sort_union,using_union,using intersect,using sort_intersection:
using intersect:表示使用and的各个索引的条件时,该信息表示是从处理结果获取交集。
using union:表示使用or连接各个使用索引的条件时,该信息表示从处理结果获取并集。
using sort_union和using sort_intersection:与前面两个对应的类似,只是他们是出现在用and和or查询信息量大时,先查询主键,然后进行排序合并后,才能读取记录并返回。 - H:using temporary:表示使用了临时表存储中间结果。临时表可以是内存临时表和磁盘临时表,执行计划中看不出来,需要查看status变量,used_tmp_table,used_tmp_disk_table才能看出来。
- I:using where:表示存储引擎返回的记录并不是所有的都满足查询条件,需要在server层进行过滤。查询条件中分为限制条件和检查条件,5.6之前,存储引擎只能根据限制条件扫描数据并返回,然后server层根据检查条件进行过滤再返回真正符合查询的数据。5.6.x之后支持ICP特性,可以把检查条件也下推到存储引擎层,不符合检查条件和限制条件的数据,直接不读取,这样就大大减少了存储引擎扫描的记录数量。extra列显示using index condition。
- J:firstmatch(tb_name):5.6.x开始引入的优化子查询的新特性之一,常见于where字句含有in()类型的子查询。如果内表的数据量比较大,就可能出现这个。
- K:loosescan(m..n):5.6.x之后引入的优化子查询的新特性之一,在in()类型的子查询中,子查询返回的可能有重复记录时,就可能出现这个。
Index是指用到索引覆盖,效率非常高
Using where 是指只靠索引无法定位。还需要where判断
Using temporary 指用上了临时表,ground by 与 order by 不同列时或ground by 与 order by 别的表的列
Using filesort 文件排序(文件可能在磁盘,也可能在内存)
三、OPTIMIZER_TRACE
从MySQL5.6版本开始,optimizer_trace 可支持把MySQL查询执行计划树打印出来,对DBA深入分析SQL执行计划,COST成本都非常有用,打印的内部信息比较全面。默认是关闭的,功能支持动态开关,因为对性能有20%左右影响,只建议分析问题时,临时开启。
1. 默认是关闭的
|
|
| Variable_name | Value |
|---|---|
| optimizer_trace | enabled=off,one_line=off |
1 row in set (0.05 sec)
2.演示 optimizer_trace 简单的使用流程:
|
|
官方文档给出了一个不错的例子,比这里的这个要复杂多了,有兴趣的同学可自行翻阅:
http://dev.mysql.com/doc/internals/en/tracing-example.html
四、SHOW PROCESSLIST
SHOW PROCESSLIST显示哪些线程正在运行。您也可以使用mysqladmin processlist语句得到此信息。如果您有SUPER权限,您可以看到所有线程。否则,您只能看到您自己的线程
MySQL保留一个额外的连接,让拥有SUPER权限的 账户使用,以确保管理员能够随时连接和检查系统(假设您没有把此权限给予所有的用户)。
|
|
介绍一下八个参数:
- id #ID标识,要kill一个语句的时候很有用
- use #当前连接用户
- host #显示这个连接从哪个ip的哪个端口上发出
- db #数据库名
- command #连接状态,一般是休眠(sleep),查询(query),连接(connect)
- time #连接持续时间,单位是秒
- state #显示当前sql语句的状态
- info #显示这个sql语句
其中state的状态十分关键,下表列出state主要状态和描述:
| 状态 | 描述 |
|---|---|
| Checking table | 正在检查数据表(这是自动的)。 |
| Closing tables | 正在将表中修改的数据刷新到磁盘中,同时正在关闭已经用完的表。这是一个很快的操作,如果不是这样的话,就应该确认磁盘空间是否已经满了或者磁盘是否正处于重负中。 |
| Connect Out | 复制从服务器正在连接主服务器。 |
| Copying to tmp table on disk | 由于临时结果集大于tmp_table_size,正在将临时表从内存存储转为磁盘存储以此节省内存。 |
| Creating tmp table | 正在创建临时表以存放部分查询结果。 |
| deleting from main table | 服务器正在执行多表删除中的第一部分,刚删除第一个表。 |
| deleting from reference tables | 服务器正在执行多表删除中的第二部分,正在删除其他表的记录。 |
| Flushing tables | 正在执行FLUSH TABLES,等待其他线程关闭数据表。 |
| Killed | 发送了一个kill请求给某线程,那么这个线程将会检查kill标志位,同时会放弃下一个kill请求。MySQL会在每次的主循环中检查kill标志位,不过有些情况下该线程可能会过一小段才能死掉。如果该线程程被其他线程锁住了,那么kill请求会在锁释放时马上生效。 |
| Locked | 被其他查询锁住了。 |
| Sending data | 正在处理SELECT查询的记录,同时正在把结果发送给客户端。 |
| Sorting for group | 正在为GROUP BY做排序。 |
| Sorting for order | 正在为ORDER BY做排序。 |
| Opening tables | 这个过程应该会很快,除非受到其他因素的干扰。例如,在执ALTER TABLE或LOCK TABLE语句行完以前,数据表无法被其他线程打开。正尝试打开一个表。 |
| Removing duplicates | 正在执行一个SELECT DISTINCT方式的查询,但是MySQL无法在前一个阶段优化掉那些重复的记录。因此,MySQL需要再次去掉重复的记录,然后再把结果发送给客户端。 |
| Reopen table | 获得了对一个表的锁,但是必须在表结构修改之后才能获得这个锁。已经释放锁,关闭数据表,正尝试重新打开数据表。 |
| Repair by sorting | 修复指令正在排序以创建索引。 |
| Repair with keycache | 修复指令正在利用索引缓存一个一个地创建新索引。它会比Repair by sorting慢些。 |
| Searching rows for update | 正在讲符合条件的记录找出来以备更新。它必须在UPDATE要修改相关的记录之前就完成了。 |
| Sleeping | 正在等待客户端发送新请求. |
| System lock | 正在等待取得一个外部的系统锁。如果当前没有运行多个mysqld服务器同时请求同一个表,那么可以通过增加–skip-external-locking参数来禁止外部系统锁。 |
| Upgrading lock | INSERT DELAYED正在尝试取得一个锁表以插入新记录。 |
| Updating | 正在搜索匹配的记录,并且修改它们。 |
| User Lock | 正在等待GET_LOCK()。 |
| Waiting for tables | 该线程得到通知,数据表结构已经被修改了,需要重新打开数据表以取得新的结构。然后,为了能的重新打开数据表,必须等到所有其他线程关闭这个表。以下几种情况下会产生这个通知:FLUSH TABLES tbl_name, ALTER TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,或OPTIMIZE TABLE。 |
| waiting for handler insert | INSERT DELAYED已经处理完了所有待处理的插入操作,正在等待新的请求。 |
mysql 查看当前连接数
命令: show processlist;
如果是root帐号,你能看到所有用户的当前连接。如果是其它普通帐号,只能看到自己占用的连接。
show processlist;只列出前100条,如果想全列出请使用show full processlist;
MySQL 5.7版本,可以通过sys.innodb_lock_waits 表查到。
|
|

可以看到,这个信息很全,4号线程是造成堵塞的罪魁祸首。而干掉这个罪魁祸首的方式,就是KILL QUERY 4或KILL 4。
不过,这里不应该显示“KILL QUERY 4”。这个命令表示停止4号线程当前正在执行的语句,而这个方法其实是没有用的。因为占有行锁的是update语句,这个语句已经是之前执行完成了的,现在执行KILL QUERY,无法让这个事务去掉id=1上的行锁。
实际上,KILL 4才有效,也就是说直接断开这个连接。这里隐含的一个逻辑就是,连接被断开的时候,会自动回滚这个连接里面正在执行的线程,也就释放了id=1上的行锁。
mysql> show status;
SHOW STATUS命令会显示每个服务器变量的名字和值,状态变量是只读的。我们可以在MySQL客户端下运行SHOW STATUS或者在命令行运用mysqladmin extended-status来查看这些变量。如果使用SQL命令,可以使用LIKE或者WHERE来限制结果。LIKE可以对变量名做标准模式匹配。(大概300多条数据 可以了解一下)
SHOW VARIABLES LIKE ‘%timeout%’
|
|
| 参数名 | 描述 |
|---|---|
| connect_timeout | 在获取链接时,等待握手的超时时间,只在登录时有效,登录成功这个参数就不管事了。主要是为了防止网络不佳时应用重连导致连接数涨太快,一般默认即可。 |
| delayed_insert_timeout | 这是为MyISAM INSERT DELAY设计的超时参数,在INSERT DELAY中止前等待INSERT语句的时间。 |
| innodb_lock_wait_timeout | 描述很长,简而言之,就是事务遇到锁等待时的Query超时时间。跟死锁不一样,InnoDB一旦检测到死锁立刻就会回滚代价小的那个事务,锁等待是没有死锁的情况下一个事务持有另一个事务需要的锁资源,被回滚的肯定是请求锁的那个Query。 |
| innodb_rollback_on_timeout | 这个参数关闭或不存在的话遇到超时只回滚事务最后一个Query,打开的话事务遇到超时就回滚整个事务。This variable was added in MySQL 5.1.15. |
| interactive_timeout/wait_timeout | 一个持续SLEEP状态的线程多久被关闭。线程每次被使用都会被唤醒为activity状态,执行完Query后成为interactive状态,重新开始计时。wait_timeout不同在于只作用于TCP/IP和Socket链接的线程,意义是一样的。 |
| net_read_timeout / net_write_timeout | 这个参数只对TCP/IP链接有效,分别是数据库等待接收客户端发送网络包和发送网络包给客户端的超时时间,这是在Activity状态下的线程才有效的参数 |
| slave_net_timeout | 这是Slave判断主机是否挂掉的超时设置,在设定时间内依然没有获取到Master的回应就人为Master挂掉了 |
更多的show variables like xxx 详解mysql运行时参数
https://blog.csdn.net/mooncarp/article/details/51787694