MySQL底层概述—7.优化原则及慢查询

大纲

1.Explain概述

2.Explain详解

3.索引优化数据准备

4.索引优化原则详解

5.慢查询设置与测试

6.慢查询SQL优化思路

1.Explain概述

使用Explain关键字可以模拟查询优化器来执行SQL查询语句,从而知道MySQL是如何处理SQL语句的,从而分析出查询语句和表结构的性能瓶颈。

MySQL查询过程:

图片

图片

通过Explain可以获得以下信息:

一.表的读取顺序

二.数据读取操作的操作类型

三.哪些索引可以被使用

四.哪些索引真正被使用

五.表的直接引用

六.每张表的有多少行被优化器查询了

Explain使用方式:Explain + SQL语句,通过执行Explain可以获得SQL语句执行的相关信息。

EXPLAIN SELECT * FROM L1;

图片

2.Explain详解

(1)数据准备

(2)ID字段说明

(3)select_type和table字段说明

(4)type字段说明

(5)possible_keys与key说明

(6)key_len字段说明

(7)ref字段说明

(8)rows字段说明

(9)filtered字段说明

(10)extra字段说明

(1)数据准备

-- 创建数据库CREATE DATABASE test CHARACTER SET 'utf8';
-- 创建表CREATE TABLE L1(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) );CREATE TABLE L2(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) );CREATE TABLE L3(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) );CREATE TABLE L4(id INT PRIMARY KEY AUTO_INCREMENT,title VARCHAR(100) );
-- 每张表插入3条数据INSERT INTO L1(title) VALUES('test001'),('test002'),('test003');INSERT INTO L2(title) VALUES('test004'),('test005'),('test006');INSERT INTO L3(title) VALUES('test007'),('test008'),('test009');INSERT INTO L4(title) VALUES('test010'),('test011'),('test012');

(2)ID字段说明

ID字段代表SELECT查询的序列号,它是一组数字,表示的是查询或操作表的顺序。

一.ID相同,执行顺序就是由上至下

EXPLAIN SELECT * FROM  L1,L2,L3 WHERE L1.id=L2.id AND L2.id = L3.id;

图片

二.ID不同,如果有子查询,ID号会递增

ID值越大优先级越高,越先被执行。

EXPLAIN SELECT * FROM L2 WHERE id = (SELECT id FROM L1 WHERE id = (SELECT L3.id FROM L3 WHERE L3.title = 'test007')
);

图片

(3)select_type和table字段说明

select_type表示查询类型,主要用于区别普通查询还是子查询等,table表示被操作的表。

一.SIMPLE:简单的SELECT查询,查询中不包含子查询或者UNION

EXPLAIN SELECT * FROM L1 where id = 1;

图片

二.PRIMARY:在有子查询的情况下,最外层被标记为PRIMARY

三.SUBQUERY:在SELECT或WHERE列表中包含了子查询​​​​​​​

EXPLAIN SELECT * FROM L2 WHERE id = (SELECT id FROM L1 WHERE id = (SELECT L3.id FROM L3 WHERE L3.title = 'test08')
);

图片

四.UNION:UNION连接的两个SELECT查询

在使用UNION时,左边的表的select_type是DERIVED,右边的表的select_type是UNION。

五.DERIVED:在FROM列表中包含的子查询被标记为DERIVED派生表

MySQL会递归执行这些被标记为DERIVED的子查询,然后把结果放到临时表中。

六.UNION RESULT:UNION的结果

EXPLAIN SELECT * FROM (SELECT * FROM L3 UNION SELECT * FROM L4) a;

图片

(4)type字段说明

type字段表示的是连接类型,描述了找到所需数据而使用的扫描方式。

下面给出各种连接类型,按照从最好类型到最差类型进行排序:system ->  const  -> eq_ref ->  ref  -> fulltext  -> ref_or_null  -> index_merge  ->  unique_subquery  -> index_subquery  -> range  -> index  -> ALL

简化后,可以只关注以下几种 :system  -> const  -> eq_ref  -> ref ->  range  -> index  ->  ALL

一般来说,需要保证查询至少达到range级别,最好能达到ref级别,否则就要就行SQL的优化调整。

下面介绍type字段不同值表示的含义:

一.system

表示表中仅有一行数据,这是const连接类型的一个特例,很少出现。

二.const

表示命中主键索引(primary key)或唯一索引(unique),通过主键索引或唯一索引一次就找到了数据。因为只匹配一条记录,所以被连接的部分是一个常量。如果将主键放在where条件中,MySQL就能将该查询转换为一个常量。这种类型非常快,例如以下查询:​​​​​​​

EXPLAIN SELECT * FROM L1 WHERE id = 3;  -- 为L1表的title字段添加唯一索引ALTER TABLE L1 ADD UNIQUE(title);EXPLAIN SELECT * FROM L1 WHERE title = 'test001';

图片

三.eq_ref

表示的是使用了唯一索引。比如连表查询中,对于前一个表中的每一行,后表只有一行被扫描。除了system和const类型之外,这是最好的连接类型。只有在连表时使用的索引都是主键或唯一索引时,才会出现这种类型,例如以下查询:

EXPLAIN SELECT L1.id,L1.title FROM L1 LEFT JOIN L2 ON L1.id = L2.id;

图片

四.ref

表示使用了普通索引,即非唯一性索引。比如连表时对于前表的每一行,后表可能有多于一行的数据被扫描,例如以下查询:​​​​​​​

-- 为L1表的title字段添加普通索引ALTER TABLE L1 ADD INDEX idx_title (title);EXPLAIN SELECT * FROM L1 INNER JOIN L2 ON L1.title = L2.title;-- 如果L1表的title字段没有唯一索引,只有普通索引,如下查询也是refEXPLAIN SELECT * FROM L1 WHERE title = 'test001';

图片

五.range

表示的是进行了索引上的范围查询,检索了给定范围的行,比如between、in函数、>都是典型的范围查询,例如以下查询:

EXPLAIN SELECT * FROM L1 WHERE L1.id BETWEEN 1 AND 10;

图片

注意:当in函数中的数据很大时,可能会导致效率下降,最终不走索引。

六.index

当可以使用索引覆盖,但需要扫描全部索引记录时,则type为index。

当需要执行全表扫描,且需要对主键进行排序时,则type也为index。

所以如果type的值等于index,那么就需要进行优化了。因为出现index表示没有通过索引进行过滤,需要扫描索引的全部数据。index会遍历扫描索引树,比ALL快一些。如果索引文件过大,index的速度还是会很慢的。

总结:

当遍历二级索引不需要回表或者主键排序全表扫描时,type就为index。

注意:

使用索引进行排序分组时,可能会出现这种type值为index的情况。比如进行统计操作时,会出现type值为index的情况。​​​​​​​

EXPLAIN SELECT * FROM L2 GROUP BY id ORDER BY id;-- 该count查询需要通过扫描索引上的全部数据来计数EXPLAIN SELECT count(*) FROM L2;

图片

七.ALL

表示没有使用到任何索引,连表查询时对于前表的每一行,后表都要被全表扫描。

EXPLAIN SELECT * FROM L3 inner join L4 on L3.title = L4.title;

图片

总结各类type类型的特点:

system:不进行磁盘IO,查询系统表,仅仅返回一条数据。

const:查找主键索引,最多返回1条或0条数据,属于精确查找。

eq_ref:查找唯一性索引,返回数据最多一条,属于精确查找。

ref:查找非唯一性索引,返回匹配的多条数据,属于精确查找。

range:查找索引中给定范围的行,属于范围查找(>、<、in、between)。

index:使用了索引但扫描全部了,比all快,因索引文件比数据文件小。

index:比如遍历二级索引不需要回表或者主键排序全表扫描。

all:不使用任何索引,直接进行全表扫描。

(5)possible_keys与key说明

一.possible_keys

表示可能用于查询的表上的索引。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。

二.key

表示实际使用的索引。若为null,则表示没有使用到索引或索引失效。查询中若使用了覆盖索引,则该索引仅出现在key列表中。

情形一:理论和实际都用到了索引

EXPLAIN SELECT * FROM L1 WHERE id = 1;

图片

情形二:理论上没有使用索引,但实际上使用了

EXPLAIN SELECT L3.id FROM L3;

图片

情形三:理论和实际上都没有使用索引

EXPLAIN SELECT * FROM L3 WHERE title = 'test007';

图片

(6)key_len字段说明

表示索引中使用的字节数,通过该列可以计算查询中使用索引的长度。key_len字段能够帮我们检查是否充分利用了索引,ken_len越长越好,说明索引使用的越充分。

一.创建表​​​​​​​

CREATE TABLE L5(    a INT PRIMARY KEY,    b INT NOT NULL,    c INT DEFAULT NULL,    d CHAR(10) NOT NULL);

二.使用EXPLAIN进行测试​​​​​​​

-- 下面的查询只用到了主键a的索引EXPLAIN SELECT * FROM L5 WHERE a > 1 AND b = 1;

观察key_len的值,用到了主键索引,是int类型的,所以key_len是4字节。

图片

三.为b字段添加索引,进行测试​​​​​​​

ALTER TABLE L5 ADD INDEX idx_b(b);-- 执行SQL,这次将b字段也作为条件EXPLAIN SELECT * FROM L5 WHERE a > 1 AND b = 1;

ken_len还是4。

图片

四.为c、d字段添加联合索引,然后进行测试

ALTER TABLE L5 ADD INDEX idx_c_b(c,d);EXPLAIN SELECT * FROM L5 WHERE c = 1 AND d = 'A';

图片

c字段是int类型4个字节,d字段char(10)代表的是10个字符30个字节。因为数据库的字符集是utf8,一个字符3个字节。d字段是char(10)代表的是10个字符相当30个字节。多出的一个字节用来表示是联合索引。

下面这个例子虽然使用了联合索引,但没充分利用索引,还有优化空间。因为可以根据ken_len的长度推测出该联合索引只使用一部分。

EXPLAIN SELECT * FROM L5 WHERE c = 1;

图片

(7)ref字段说明

表示的是显示索引的哪一列被使用了,如果可能的话,最好是一个常数。表示的是哪些列或常量被用于查找索引列上的值。

如下的"L1.id=1"中,由于1是常量,所以ref = const,此时的ref = const表示着查询过程中使用到了常量。

EXPLAIN SELECT * FROM L1 WHERE L1.id = 1;

图片

(8)rows字段说明

表示MySQL为了找到所需的记录,一共访问了多少行(预估的)。L3中的title没有添加索引,所以L3中有3条记录,就需要访问3条记录。

EXPLAIN SELECT * FROM L3,L4 WHERE L3.id = L4.id AND L3.title LIKE 'test007';

图片

需要注意的是rows只是一个估算值,并不准确。所以rows行数过大的问题并不值得过多考虑,主要分析的还是索引是否使用正确了。

(9)filtered字段说明

它指返回结果的行占需要读到的行(rows列的值)的百分比。

(10)extra字段说明

Extra是EXPLAIN输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息。

一.准备数据​​​​​​​

CREATE TABLE users (    uid INT PRIMARY KEY AUTO_INCREMENT,    uname VARCHAR(20),    age INT(11));INSERT INTO users VALUES(NULL, 'lisa', 10);INSERT INTO users VALUES(NULL, 'lisa', 10);INSERT INTO users VALUES(NULL, 'rose', 11);INSERT INTO users VALUES(NULL, 'jack', 12);INSERT INTO users VALUES(NULL, 'sam', 13);

二.Using filesort(需要进行文件排序)

执行结果Extra为Using filesort,说明得到所需结果集,需要对所有记录进行文件排序。表示执行的SQL语句性能极差,需要进行优化。

下面就是在一个没有建立索引的列上进行order by,此时会触发filesort。优化方案是,在order by的列上添加索引,避免每次查询都全量排序。

EXPLAIN SELECT * FROM users ORDER BY age;

图片

三.Using temporary

表示使用了临时表来存储结果集,常见于排序和分组查询。

EXPLAIN SELECT COUNT(*),uname FROM users GROUP BY uname;

图片

四.Using where

表示使用了全表扫描或者在查找时使用索引的情况下,还有查询条件不在索引字段中需要回表。

注意一:返回所有记录的SQL,不使用where条件过滤数据,大概率不符合预期,这类SQL往往需要进行优化。

注意二:使用了where条件的SQL,并不代表不需要优化,往往需要配合explain结果中的type(连接类型)来综合判断。例如下面查询的age未设置索引,所以返回的type为ALL,仍有优化空间,可建立索引优化查询。

EXPLAIN SELECT * FROM users WHERE age = 10;

图片

五.Using index

表示直接访问索引就能获取所需数据(覆盖索引),不需要回表。​​​​​​​

-- 为uname创建索引ALTER TABLE users ADD INDEX idx_uname(uname);EXPLAIN SELECT uid,uname FROM users WHERE uname='lisa';

图片

六.Using join buffer

表示使用了连接缓存,还会显示join连接查询时使用的算法。​​​​​​​

EXPLAIN SELECT * FROM users u1 LEFT JOIN     (SELECT * FROM users WHERE age = 1) u2 ON u1.age = u2.age;

图片

Using join buffer(Block Nested Loop)说明,需要进行嵌套循环计算。这里每个表都有五条记录,内外表查询的type都为ALL。两个表通过字段age进行关联,且age字段未建立索引。

七.Using index condition

表示的是使用了索引,但是只使用了索引的一部分。一般发生在使用联合索引时,需要回表查询。

EXPLAIN SELECT * FROM L5 WHERE c > 10 AND d = '';

图片

八.Extra主要指标的含义总结

using index:查找时使用了覆盖索引的时候就会出现,不需要回表。

using where:查找时使用索引的情况下需要回表或全表扫描。

using index condition:查找时使用了索引但只用一部分索引需要回表。

Using filesort:在一个没有建立索引的列上order by,发生文件排序。

Using temporary:使用了临时表存储结果集,常见于排序和分组查询。

当遍历二级索引不需要回表或者主键排序全表扫描时,type就为index。

查找非唯一性索引,返回匹配的多条数据,type就为ref。

查找唯一性索引,返回匹配的数据最多一条,type就为eq_ref。

查找索引中给定范围的行,type就为range。

3.索引优化数据准备

(1)创建数据库、表,插入数据​​​​​​​

create database idx_optimize character set 'utf8';CREATE TABLE users(    id INT PRIMARY KEY AUTO_INCREMENT,    user_name VARCHAR(20) NOT NULL COMMENT '姓名',    user_age INT NOT NULL DEFAULT 0 COMMENT '年龄',    user_level VARCHAR(20) NOT NULL COMMENT '用户等级',    reg_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '注册时间');INSERT INTO users(user_name,user_age,user_level,reg_time)VALUES('tom',17,'A',NOW()),('jack',18,'B',NOW()),('lucy',18,'C',NOW());

(2)创建联合索引

ALTER TABLE users ADD INDEX idx_nal (user_name,user_age,user_level) USING BTREE;

4.索引优化原则详解

(1)最左侧列匹配和最左前缀匹配法则

(2)不要在索引列上做任何计算

(3)范围之后全失效

(4)避免使用is null、is not null、!= 、or

(5)like以%开头会使索引失效

(6)索引优化原则总结

(1)最左侧列匹配和最左前缀匹配法则

如果创建的是联合索引,就要遵循该法则。where后面的条件需从索引的最左侧列开始,且不能跳过索引中的列。如果where只匹配一个列,那么该列在索引最左侧,且只匹配前缀字段。

一.最左侧列匹配和最左前缀匹配的场景

场景1:按照索引字段顺序使用,三个字段都使用了索引,没有问题。​​​​​​​

EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 AND user_level = 'A';

图片

场景2:直接跳过user_name使用索引字段,索引无效,未使用到索引。

EXPLAIN SELECT * FROM users WHERE user_age = 17 AND user_level = 'A';

图片

场景3:  不按照创建联合索引的顺序,使用索引。

EXPLAIN SELECT * FROM users WHERE user_age = 17 AND user_name = 'tom' AND user_level = 'A';

图片

where后面查询条件顺序是user_age、user_level、user_name,这与创建的索引顺序user_name、user_age、user_level不一致。为什么还是使用了索引,原因是MySQL底层优化器对其进行了优化。

场景4:只要包含最左侧字段,索引就可以生效

但从key_len可知只是用到索引的一部分。

EXPLAIN SELECT * FROM users WHERE user_name = 'tom';

图片

二.最左侧列匹配和最左前缀匹配的原理

InnoDB创建联合索引的规则是:

首先会对联合索引最左边的字段进行排序,例子中是user_name。在第一个字段的基础之上再对第二个字段进行排序,例子中是user_age。所以最佳左前缀原则其实是和B+树的结构有关系,最左字段肯定是有序的,第二个字段则是无序的。

联合索引的排序方式是:

先按第一个字段进行排序,如果第一个字段相等再根据第二个字段排序。所以如果直接使用第二个字段user_age通常是使用不到索引的。

(2)不要在索引列上做任何计算

不要在索引列上做任何操作,否则会导致索引失效,从而转向全表扫描。比如计算、使用函数、自动或手动进行类型转换(字符串不加双引号)。

一.插入数据

INSERT INTO users(user_name,user_age,user_level,reg_time) VALUES('11223344',22,'D',NOW());

场景1:使用系统函数left()函数,对user_name进行操作

EXPLAIN SELECT * FROM users WHERE LEFT(user_name, 6) = '112233';

图片

场景2:字符串不加单引号(隐式类型转换)

对于varchar类型的字段,如果查询时不加单引号就会进行隐式转换,导致索引失效转向全表扫描。

EXPLAIN SELECT * FROM users WHERE user_name = 11223344;

图片

(3)范围之后全失效

where条件中如果有范围条件,并且范围条件之后还有其他过滤条件,那么范围条件之后的列就都将会索引失效。

场景1:条件单独使用user_name时,type=ref、key_len=62。​​​​​​​

-- 条件只有一个 user_nameEXPLAIN SELECT * FROM users WHERE user_name = 'tom';

图片

场景2:条件增加一个user_age(使用常量等值),type= ref、key_len = 66。

EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17;

图片

场景3:使用全值匹配,type = ref、key_len = 128,索引都利用上了。

EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age = 17 AND user_level = 'A';

图片

场景4:使用范围条件时,avg > 17、type = range、key_len = 66。与场景3比较,可发现user_level索引没用上。

EXPLAIN SELECT * FROM users WHERE user_name = 'tom' AND user_age > 17 AND user_level = 'A';

图片

(4)避免使用is null、is not null、!= 、or

一.使用is null会使索引失效

EXPLAIN SELECT * FROM users WHERE user_name IS NULL;

图片

Impossible Where:表示where条件不成立,不能返回任何行。

二.使用is not null会使索引失效

EXPLAIN SELECT * FROM users WHERE user_name IS NOT NULL;

图片

三.使用!=和or会使索引失效​​​​​​​

EXPLAIN SELECT * FROM users WHERE user_name != 'tom';EXPLAIN SELECT * FROM users WHERE user_name = 'tom' or user_name = 'jack';

图片

(5)like以%开头会使索引失效

一.like查询中%出现在左边则索引失效,%出现在右边索引未失效

场景1:两边都有%或者%在左边,索引都会失效​​​​​​​

EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom%';EXPLAIN SELECT * FROM users WHERE user_name LIKE '%tom';

图片

场景2:%在右边,索引生效

EXPLAIN SELECT * FROM users WHERE user_name LIKE 'tom%';

图片

二.解决%出现在左边索引失效的方法——使用覆盖索引​​​​​​​

EXPLAIN SELECT user_name FROM users WHERE user_name LIKE '%jack%';EXPLAIN SELECT user_name,user_age,user_level FROM users WHERE user_name LIKE '%jack%';

图片

对比场景1可以知道:通过使用覆盖索引type = index,并且extra = Using index,从原来的全表扫描变成了全索引扫描,也就是索引的全表扫描。

三.like失效的原理

原理一:%号在右

由于B+树的索引顺序,是按照首字母的大小进行排序,而%号在右时的匹配又会匹配首字母,所以能在B+树上进行有序的查找。也就是查找出首字母符合要求的数据,所以%号在右可以用到索引。

原理二:%号在左是匹配字符串尾部的数据

由于尾部的字母是没有顺序的,所以不能按索引顺序查询,用不到索引。

原理三:两个%%号

这个是查询任意位置的字母满足条件即可。只有首字母是进行索引排序的,其他位置的字母都是相对无序的,所以查找任意位置的字母是用不上索引的。

(6)索引优化原则总结

一.最左侧列匹配和最左前缀匹配

二.索引列上不计算不转换

三.范围之后全失效

四.最好使用覆盖索引

五.!=、is null、is not null、or会索引失效

六.like百分号加右边,加左边导致索引失效的解决方法是使用覆盖索引

5.慢查询设置与测试

(1)慢查询介绍

(2)慢查询参数

(3)慢查询配置方式

(4)慢查询测试

(5)慢日志内容

(1)慢查询介绍

MySQL的慢查询全名是慢查询日志,是MySQL提供的一种日志记录。慢查询日志会记录在MySQL中响应时间超过阈值的语句。MySQL数据库默认不启动慢查询日志,需要手动来设置这个参数。

如果不是调优需要的话,一般不建议启动该参数。因为开启慢查询日志会或多或少带来一定的性能影响,慢查询日志支持将日志记录写入文件和数据库表。

(2)慢查询参数

执行下面的语句​​​​​​​

mysql> show variables like '%slow_query_log%';+---------------------+------------------------------+| Variable_name       | Value                        |+---------------------+------------------------------+| slow_query_log      | ON                           || slow_query_log_file | /var/lib/mysql/test-slow.log |+---------------------+------------------------------+
mysql> show variables like '%long_query%';+-----------------+-----------+| Variable_name   | Value     |+-----------------+-----------+| long_query_time | 10.000000 |+-----------------+-----------+

MySQL慢查询的相关参数解释:

一.slow_query_log:是否开启慢查询日志。

二.slow-query-log-file:慢查询日志存储路径。

三.long_query_time:慢查询阈值,查询时间多于设定阈值则记录日志。

(3)慢查询配置方式

一.默认情况下slow_query_log的值为OFF,表示慢查询日志是禁用的​​​​​​​

mysql> show variables like '%slow_query_log%';+---------------------+------------------------------+| Variable_name       | Value                        |+---------------------+------------------------------+| slow_query_log      | ON                           || slow_query_log_file | /var/lib/mysql/test-slow.log |+---------------------+------------------------------+

二.可以通过设置slow_query_log的值来开启

mysql> set global slow_query_log=1;

三.set global slow_query_log=1开启慢查询日志当前生效重启失效

如果要永久生效,就必须修改配置文件my.cnf,其它系统变量也是如此。​​​​​​​

-- 编辑配置vim /etc/my.cnf
-- 添加如下内容slow_query_log =1slow_query_log_file=/var/lib/mysql/ruyuan-slow.log
-- 重启MySQLservice mysqld restart
mysql> show variables like '%slow_query%';+---------------------+--------------------------------+| Variable_name       | Value                          |+---------------------+--------------------------------+| slow_query_log      | ON                             || slow_query_log_file | /var/lib/mysql/ruyuan-slow.log |+---------------------+--------------------------------+

四. 开启了慢查询日志后,什么样的SQL才会记录到慢查询日志里

这个由参数long_query_time控制,默认long_query_time的值为10秒。​​​​​​​

mysql> show variables like 'long_query_time';+-----------------+-----------+| Variable_name   | Value     |+-----------------+-----------+| long_query_time | 10.000000 |+-----------------+-----------+
mysql> set global long_query_time=1;Query OK, 0 rows affected (0.00 sec)
mysql>  show variables like 'long_query_time';+-----------------+-----------+| Variable_name   | Value     |+-----------------+-----------+| long_query_time | 10.000000 |+-----------------+-----------+

五.修改变量long_query_time,但查询值还是10

执行命令set global long_query_time=1后,需要重新连接或者打开新开会话才能看到修改值。​​​​​​​

mysql> show variables like 'long_query_time';+-----------------+----------+| Variable_name   | Value    |+-----------------+----------+| long_query_time | 1.000000 |+-----------------+----------+

六.log_output参数是指定日志的存储方式

log_output=FILE表示将日志存入文件,默认值是FILE。log_output=TABLE表示将日志存入数据库,这样日志信息就会被写入到mysql.slow_log表中。

MySQL数据库可以同时支持两种日志存储方式,配置的时候以逗号隔开即可,如:log_output='FILE,TABLE'。

日志记录到系统的专用日志表中,要比记录到文件耗费更多的系统资源。因此如果启用慢查询日志+获得更高系统性能,则建议优先记录到文件。​​​​​​​

mysql> SHOW VARIABLES LIKE '%log_output%';+---------------+-------+| Variable_name | Value |+---------------+-------+| log_output    | FILE  |+---------------+-------+

七.开启系统变量让未使用索引的查询也被记录到慢查询日志中

这个系统变量就是log-queries-not-using-indexes,所以在进行调优时,可以开启这个选项。​​​​​​​

mysql> show variables like 'log_queries_not_using_indexes';+-------------------------------+-------+| Variable_name                 | Value |+-------------------------------+-------+| log_queries_not_using_indexes | OFF   |+-------------------------------+-------+
mysql> set global log_queries_not_using_indexes=1;Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'log_queries_not_using_indexes';+-------------------------------+-------+| Variable_name                 | Value |+-------------------------------+-------+| log_queries_not_using_indexes | ON    |+-------------------------------+-------+

(4)慢查询测试

一.执行test_index.sql脚本,监控慢查询日志内容​​​​​​​

[root@localhost mysql]# tail -f /var/lib/mysql/test-slow.log 
/usr/sbin/mysqld, Version: 5.7.30-log (MySQL Community Server (GPL)). started with:
Tcp port: 0  Unix socket: /var/lib/mysql/mysql.sock
Time                 Id Command    Argument

二. 执行下面的SQL,执行超时(超过1秒)我们去查看慢查询日志​​​​​​​

SELECT * FROM test_index WHERE hobby = '20009951' OR hobby = '10009931' OR hobby = '30009931'OR dname = 'name4000' OR dname = 'name6600' ;

(5)慢日志内容

我们得到慢查询日志后,最重要的一步就是去分析这个日志。先来看慢日志里到底记录了哪些内容,如下是慢日志里其中一条记录,可以看到有时间戳、用户、查询时长及具体的SQL等信息。​​​​​​​

Time                 Id Command    Argument
# Time: 2022-02-23 T03:55:15. 336037Z
# User@Host: root[root] @ localhost []  Id:     6
# Query_time: 2.375219  Lock_time: 0.000137 Rows_sent: 3  Rows_examined: 5000000
use db4;
SET timestamp=1645588515;
SELECT * FROM test_index WHERE  hobby = '20009961' OR hobby = '10009941' OR hobby = '30009961' OR dname = 'name4001' OR dname = 'name6601';

Time:执行时间;

Users:用户信息;

Query_time:查询时长;

Lock_time:等待锁时长;

Rows_sent:结果行统计数量;

Rows_examined:扫描的行数;

6.慢查询SQL优化思路

(1)SQL性能下降的原因

(2)慢查询优化思路

(1)SQL性能下降的原因

导致SQL执行性能下降的原因可体现在以下两方面:

一.等待时间长

锁表导致查询一直处于等待状态。

二.执行时间长

查询语句没优化、索引失效、关联查询太多join、机器及参数没调优。

(2)慢查询优化思路

一.优先选择优化高并发执行的SQL

因为高并发的SQL出现问题带来后果更严重,比如下面两种情况:SQL1每小时执行10000次,每次20个IO,优化后每次18个IO,每小时节省2万次IO;SQL2每小时10次,每次20000个IO,每次优化减少2000个IO,每小时节省2万次IO。此时SQL2更难优化,SQL1更好优化。但是第一种属于高并发SQL,更急需优化,因为成本更低。

二.定位优化对象的性能瓶颈

在去优化SQL时,选择优化分方向有三个:

方向1:IO,数据访问消耗了太多时间,查看是否正确使用索引。

方向2:CPU,数据运算花费了太多时间,数据的运算分组、排序是不是有问题。

方向3:网络带宽,加大网络带宽。

三.明确优化目标

根据数据库当前状态、当前SQL的具体功能,来确定最好情况下消耗的资源和最差情况下消耗的资源。因为优化的结果只有一个,即给用户一个好的体验。

四.从explain执行计划入手

只有explain能告诉我们当前SQL的执行状态。

五.永远用小的结果集驱动大的结果集

小的数据集驱动大的数据集,减少内层表读取次数。​​​​​​​

//类似于嵌套循环
for (int i = 0; i < 5; i++) {for (int i = 0; i < 1000; i++) {}
}

六.尽可能在索引中完成排序

排序操作用得比较多,所以order by后面的字段尽量使用上索引。因为索引本来就是排好序的,所以速度很快。没有索引的话,就需要从表中拿数据,在内存中进行排序。如果内存空间不够还会发生临时文件落盘操作。

七.只获取自己需要的列

不要使用select  *,因为select * 很可能不使用索引,而且数据量过大。

八.只使用最有效的过滤条件

where后面的条件并非越多越好,应该用最短的路径访问到数据。

九.尽可能避免复杂的join和子查询

每条SQL的JOIN操作建议不要超过三张表。将复杂的SQL,拆分成多个小的SQL,单个表执行,然后对获取的结果在程序中进行封装。因为如果join占用的资源比较多,会导致其他进程等待时间变长。

十.合理设计并利用索引

也就是合理判断是否需要创建索引,以及合理选择合适索引。

(3)如何判定是否需要创建索引

一.频繁作为查询条件的字段应该创建索引

二.唯一性太差的字段不适合单独创建索引,即使它频繁作为查询条件

唯一性太差的字段主要是指哪些呢?如状态字段、类型字段等。这些字段中的数据可能总共就是那么几个几十个数值重复使用。当一条Query所返回的数据超过了全表的15%时,就不应该再使用索引扫描来完成这个Query了。

三.更新非常频繁的字段不适合创建索引

因为索引中的字段被更新时,不仅要更新表的数据,还要更新索引数据。

四.不会出现在WHERE子句中的字段不该创建索引

(4)如何选择合适索引

一.单键索引,尽量选择针对当前Query过滤性更好的索引。

二.联合索引,当前查询中过滤性最好的字段在索引字段顺序中排列靠前。

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

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

相关文章

【前端】Vue3+Vite如何进行多环境配置呢

在项目或产品的迭代过程中需要分不同的环境&#xff0c;那么使用vitevue3开发时&#xff0c;该如何进行配置呢 1、添加配置文件 .env.xxx .env.xxx 需要与src在同一级目录下 例如&#xff1a; 开发环境&#xff1a; .env.development 开发环境&#xff1a; .env.test 生产环…

FreeSWITCH 简单图形化界面36 -使用mod_sms发送短消息

FreeSWITCH 简单图形化界面36 -使用mod_sms发送短消息 0、测试环境1、mod_sms模块安装2、编写聊天规则2.1 使用xml文件测试一下 2.2 使用脚本文件测试一下 0、测试环境 http://myfs.f3322.net:8020/ 用户名&#xff1a;admin&#xff0c;密码&#xff1a;admin FreeSWITCH界面…

广域网技术

企业需要通过广域网将这些分散在不同地理位置的分支机构连接起来 早期广域网技术概述 广域网&#xff1a;连接不同地区局域网的网络&#xff0c;能够横跨几个洲提供远距离通信&#xff0c;形成国际性的远程网络 广域网设备角色介绍&#xff1a; CE&#xff1a;用户端连接服务…

[GKCTF 2021]签到

[GKCTF 2021]签到 wireshark跟踪http流&#xff0c;基本编解码&#xff0c;倒叙&#xff0c;栅栏密码 找到cat /f14g 把包里返回的字符串先hex解码&#xff0c;再base64解码&#xff0c;看到一个时间是倒叙&#xff0c;不含flag 继续往下面翻&#xff0c;可以看到cat%2Ff14g%7…

ROS VSCode调试方法

VSCode 调试 Ros文档 1.编译参数设置 cd catkin_ws catkin_make -DCMAKE_BUILD_TYPEDebug2.vscode 调试插件安装 可在扩展中安装(Ctrl Shift X): 1.ROS 2.C/C 3.C Intelliense 4.Msg Language Support 5.Txt Syntax 3.导入已有或者新建ROS工作空间 3.1 导入工作…

Socket编程(TCP/UDP详解)

前言&#xff1a;之前因为做项目和找实习没得空&#xff0c;计算机网络模块并没有写成博客&#xff0c;最近得闲了&#xff0c;把计算机网络模块博客补上。 目录 一&#xff0c;UDP编程 1&#xff09;创建套接字 2&#xff09;绑定端口号 3&#xff09;发送与接收数据 4&…

虚拟机VMware安装OpenWrt镜像

前提已经安装VMware Workstation Pro,我使用的是VM16 一.下载OpenWrt系统固件 固件有很多种&#xff0c;我选择下面这个链接的固件: Index of /releases/23.05.3/targets/x86/64/ 二.把固件转换成虚拟机能识别的格式 转换工具下载地址&#xff1a;https://www.starwindsoft…

【Canvas与雷达】点鼠标可暂停金边蓝屏雷达显示屏

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>点鼠标可暂停金边蓝屏雷达显示屏 Draft1</title><style typ…

计算机编码存储+char占用空间+final作用

内存中存储的是对应的编码&#xff0c;与对应的形状库一起能够在显示器显示出来对应的字符。 磁盘中存储的是文件信息。 内存中存储的是变量&#xff08;虽然也是在磁盘里&#xff0c;等到使用的时候再调入进来&#xff09;。 因为编码实质就是二进制串&#xff0c;所以也可以比…

vue3项目搭建-6-axios 基础配置

axios 基础配置 安装 axios npm install axios 创建 axios 实例&#xff0c;配置基地址&#xff0c;配置拦截器,目录&#xff1a;utils/http.js 基地址&#xff1a;在每次访问时&#xff0c;自动作为相对路径的根 // axios 基础封装 import axios from "axios";…

2-2-18-9 QNX系统架构之文件系统(一)

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…

Python基于滑动窗口CNN损伤梁桥数据、故宫城墙图像数据分类可视化|数据分享

全文链接&#xff1a;https://tecdat.cn/?p38442 分析师&#xff1a;Yufei Guo 在现代土木结构工程领域&#xff0c;结构损伤的准确识别与定位对于保障基础设施的安全性和耐久性具有极为关键的意义。传统的人工检查方法&#xff0c;如目视检查以及借助专业设备进行检测&#x…

MyBatis的if标签的基本使用

在MyBatis框架中&#xff0c;if标签用于在构建SQL语句时&#xff0c;根据参数条件判断的结果&#xff0c;动态地选择加入或不加where条件中。 一 常见使用 在使用MyBatis处理查询逻辑的时候&#xff0c;常用的是判断一些参数是否为空&#xff0c;列举常用的几种情况展示 1.1…

RabbitMQ原理架构解析:消息传递的核心机制

文章目录 一、RabbitMQ简介1.1、概述1.2、特性 二、RabbitMQ原理架构三、RabbitMQ应用场景3.1、简单模式3.2、工作模式3.3、发布订阅3.4、路由模式3.5 主题订阅模式 四、同类中间件对比五、RabbitMQ部署5.1、单机部署5.2、集群部署&#xff08;镜像模式&#xff09;5.3、K8s部署…

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比

NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测&#xff0c;含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…

【0346】Postgres内核 Startup Process 通过 signal 与 postmaster 交互实现 (5)

1. Startup Process 进程 postmaster 初始化过程中, 在进入 ServerLoop() 函数之前,会先通过调用 StartChildProcess() 函数来开启辅助进程,这些进程的目的主要用来完成数据库的 XLOG 相关处理。 如: 核实 pg_wal 和 pg_wal/archive_status 文件是否存在Postgres先前是否发…

说说Elasticsearch拼写纠错是如何实现的?

大家好&#xff0c;我是锋哥。今天分享关于【说说Elasticsearch拼写纠错是如何实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; 说说Elasticsearch拼写纠错是如何实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 Elasticsearch 中&…

NAT拓展

NAT ALG&#xff08;NAT应用级网&#xff09; 为某些应用层协议&#xff0c;因为其报文内容可能携带IP相关信息&#xff0c;而普通NAT转化无法将这些IP转化&#xff0c;从而导致协议无法正常运行 例如FTP&#xff0c;DHCP&#xff0c;RSTP&#xff0c;ICMP&#xff0c;IPSEC…

Flutter:封装发送验证码组件,注册页使用获取验证码并传递控制器和验证码类型

验证码&#xff1a;view import package:flutter/material.dart; import package:get/get.dart; import index.dart;class SendcodePage extends GetView<SendcodeController> {// 接收注册页面&#xff0c;传进来的手机号控制器&#xff0c;和发送验证码的类型final Tex…

【目标跟踪】Anti-UAV数据集详细介绍

Anti-UAV数据集是在2021年公开的专用于无人机跟踪的数据集&#xff0c;该数据集采用RGB-T图像对的形式来克服单个类型视频的缺点&#xff0c;包含了318个视频对&#xff0c;并提出了相应的评估标准&#xff08;the state accurancy, SA)。 文章链接&#xff1a;https://arxiv.…