当前位置: 首页 > news >正文

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过滤性更好的索引。

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

相关文章:

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

大纲 1.Explain概述 2.Explain详解 3.索引优化数据准备 4.索引优化原则详解 5.慢查询设置与测试 6.慢查询SQL优化思路 1.Explain概述 使用Explain关键字可以模拟查询优化器来执行SQL查询语句&#xff0c;从而知道MySQL是如何处理SQL语句的&#xff0c;从而分析出查询语句…...

R““有什么作用在C++中,举例说明

在C中&#xff0c;R""&#xff08;双引号前加R&#xff09;表示一个原始字符串字面量&#xff08;Raw String Literal&#xff09;&#xff0c;其主要作用是让字符串中的反斜杠\和其他特殊字符不被当作转义字符处理&#xff0c;而是保留其原始字面意义。这在处理包含…...

linux中top 命令返回数据解释

当您在 Linux 终端中运行 top 命令时,它会显示一个动态更新的系统状态视图,其中包括许多有关系统性能的数据。下面是对 top 命令返回数据的详细解释: 标题栏 top - 22:46:12 up 2 days, 3:14, 1 user, load average: 0.05, 0.07, 0.09 22:46:12:当前时间。up 2 days, 3:14…...

深入理解二叉树及其变体:平衡二叉树、红黑树、B-树和B+树

一、二叉树简介 二叉树是一种非常常见的数据结构&#xff0c;它具有以下特点&#xff1a; 每个节点最多有两个子节点&#xff0c;分别称为左子节点和右子节点。每个节点的左子树和右子树都是二叉树。 二叉树的常见操作包括&#xff1a;创建、插入、删除、查找、遍历等。下面…...

C++ 编程技巧之StrongType(1)

最近看到一个NamedType的开源库&#xff0c;被里面的Strong Type这个概念和里面的模版实现给秀了一脸&#xff0c;特此总结学习一下 GitHub - joboccara/NamedType: Implementation of strong types in C C本身是一种强类型语言&#xff0c;类型包括int、double等这些build i…...

芯片测试-smith圆图

smith圆图 &#x1f4a2;smith圆图的故事&#x1f4a2;&#x1f4a2;smith圆图中的各部分来历&#x1f4a2;&#x1f4a2;公式推导&#x1f4a2;&#x1f4a2;等电阻圆特点&#x1f4a2;&#x1f4a2;等电抗圆&#x1f4a2;&#x1f4a2;等电抗圆特点&#x1f4a2; &#x1f4a…...

HTML技术深度解析:构建现代网页的基石

引言 HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是构建网页和网上应用的标准标记语言。随着互联网技术的飞速发展&#xff0c;HTML已经成为前端开发中不可或缺的核心技术之一。本文将深入探讨HTML的基本概念、核心元素、最新发展以及在…...

Leecode刷题C语言之判断是否可以赢得数字游戏

执行结果:通过 执行用时和内存消耗如下&#xff1a; bool canAliceWin(int* nums, int numsSize) {int single_digit_sum 0;int double_digit_sum 0;for (int i 0; i < numsSize; i) {if (nums[i] < 10) {single_digit_sum nums[i];} else {double_digit_sum nums[…...

Ubuntu 关机命令

在 Ubuntu 系统中&#xff0c;有几种方法可以关机。以下是常用的关机命令及其说明&#xff1a; 1. 使用 shutdown 命令 shutdown 命令是最常用和最灵活的关机方式。它可以设置定时关机&#xff0c;并且可以发送警告消息给所有登录用户。 立即关机 sudo shutdown now定时关机…...

数据采集中,除了IP池的IP被封,还有哪些常见问题?

在数据采集的过程中&#xff0c;代理IP池的使用无疑为我们打开了一扇通往信息宝库的大门。然而&#xff0c;除了IP被封禁这一常见问题外&#xff0c;还有许多其他问题可能影响数据采集的效果。本文将探讨在数据采集中&#xff0c;除了IP被封之外&#xff0c;还可能遇到的一些常…...

【Anaconda】 创建环境报错:CondaHTTPError: HTTP 000 CONNECTION FAILED for url

问题描述 使用 Anaconda 创建环境时报错&#xff1a; CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/free/noarch/repodata.json.bz2> Elapsed: -An HTTP error occurred when trying to retrieve this URL. HTTP errors are o…...

社交电商破局之“2+1 链动模式 O2O 商城小程序源码”赋能流量困境突围

摘要&#xff1a;本文聚焦于当下商家在流量困境中挣扎的现状&#xff0c;剖析传统电商高流量成本、平台流量获取难等痛点&#xff0c;阐述私域流量池兴起的缘由与价值。重点探究“21 链动模式 O2O 商城小程序源码”如何融入社交电商架构&#xff0c;通过创新机制与线上线下融合…...

【ArcGIS Pro微课1000例】0062:ArcGIS Pro3.3.1中文版安装教程(附安装包下载)

本文讲述ArcGIS Pro3.3.1中文版安装教程(附安装包下载)。 文章目录 一、ArcGIS Pro3.3.1中文版下载二、ArcGIS Pro3.3.1中文版安装一、ArcGIS Pro3.3.1中文版下载 【订阅专栏】,获取完整安装包及专栏配套实验数据。下载后解压,如下图所示: 二、ArcGIS Pro3.3.1中文版安装…...

Linux - web服务器

四、web服务器 1、基础知识 URL&#xff1a;Uniform Resource Locator&#xff0c;统一资源定位符&#xff0c;对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示&#xff0c;是互联网上标准资源的地址。 网址格式&#xff1a;<协议>://<主机或主机名&g…...

设计模式-适配器模式-注册器模式

设计模式-适配器模式-注册器模式 适配器模式 如果开发一个搜索中台&#xff0c;需要适配或接入不同的数据源&#xff0c;可能提供的方法参数和平台调用的方法参数不一致&#xff0c;可以使用适配器模式 适配器模式通过封装对象将复杂的转换过程隐藏于幕后。 被封装的对象甚至…...

减速机润滑油更换的最佳周期是多久?

减速机是工业设备中的重要组成部分&#xff0c;润滑油的使用对于其正常运转和寿命具有至关重要的作用。那么&#xff0c;减速机多久更换一次润滑油呢&#xff1f;实际上&#xff0c;减速机润滑油的更换周期受多种因素影响&#xff0c;以下是一些具体的更换周期建议&#xff1a;…...

程序执行堆栈执行模拟

所有的文件都是在硬盘&#xff08;磁盘&#xff09;上&#xff0c;调用时先调用javac指令的jdk编译成.class然后被java指令的jre送到内存中&#xff0c;java在内存中有自己的一片区域叫JVM&#xff0c;编译进来的文件首先进入方法区。 staitc的属性就是在进入内存的时候开辟了一…...

《Python基础》之数据加密模块hashlib的用法

目录 一、简介 二、用法 步骤一、导入hashlib库 步骤二、创建哈希对象 步骤三、往哈希对象中传值 1、可以在创建对象的时候传值 2、使用updata传值 步骤四、获取经过哈希对象加密后的值 三、注意事项 1、编码问题 2、安全性 3、多次传值 四、总结 一、简介 hashli…...

安装Fcitx5输入框架和输入法自动部署脚本(来自Mark24)-Ubuntu通用

在Ubuntu22.04上安装rime中文输入法的基本教程 上述文章接近废弃。 使用新逻辑配置基本的Fcitx5的输入法。 安装 第一步&#xff0c;下载相关组件 sudo nala install vim sudo nala install ruby sudo nala install fcitx5-rime第二步&#xff0c;设置语言为Fcitx5 而非 默认…...

【IMF靶场渗透】

文章目录 一、基础信息 二、信息收集 三、flag1 四、flag2 五、flag3 六、flag4 七、flag5 八、flag6 一、基础信息 Kali IP&#xff1a;192.168.20.146 靶机IP&#xff1a;192.168.20.147 二、信息收集 Nmap -sP 192.168.20.0/24 Arp-scan -l nmap -sS -sV -p- -…...

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法&#xff0c;提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为&#xff1a; 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为&#xff0c;如进程崩溃&#xff0c;只要…...

深入了解 Adam 优化器对显存的需求:以 LLaMA-2 7B 模型为例 (中英双语)

中文版 深入了解 Adam 优化器对显存的额外需求&#xff1a;模型参数与优化器状态的显存开销分析 在深度学习模型的训练过程中&#xff0c;显存是一个关键的资源&#xff0c;尤其在处理大型语言模型或深度神经网络时。训练时的显存需求不仅包括模型参数本身&#xff0c;还涉及…...

数据分析学习

数据分析的定义 数据分析是通过对收集到的数据进行清理、转换、建模、分析和解释&#xff0c;从中提取有用的信息和洞察&#xff0c;以帮助做出更好的决策。数据分析可以应用于各种领域&#xff0c;比如商业、金融、医疗、市场营销等&#xff0c;目的是通过数据来发现模式、趋…...

PaddleOCR:一款高性能的OCR工具介绍

一、引言 随着人工智能技术的不断发展&#xff0c;光学字符识别&#xff08;OCR&#xff09;技术在各行各业得到了广泛应用。OCR技术能够将图片、扫描件等非结构化数据中的文字信息提取出来&#xff0c;转换为可编辑的文本格式。在我国&#xff0c;百度开源了一款优秀的OCR工具…...

Transformers快速入门代码解析(一):注意力机制——Attention:Scaled Dot-product Attention

Attention&#xff1a;Scaled Dot-product Attention 引言Scaled Dot-product Attention代码 引言 请注意&#xff01;&#xff01;&#xff01;本博客使用了教程Transformers快速入门中的全部代码&#xff01;&#xff01;&#xff01; 只在我个人理解的基础上为代码添加了注释…...

Git中HEAD、工作树和索引的区别

在Git版本控制系统中&#xff0c;HEAD、工作树&#xff08;Working Tree&#xff09;和索引&#xff08;Index&#xff09;是三个非常重要的概念&#xff0c;它们分别代表了不同的状态或区域&#xff0c;下面我将对这三个概念进行详细的解释。 HEAD 定义&#xff1a;HEAD是一…...

【python量化教程】如何使用必盈API的股票接口,获取最新实时交易数据

实时交易数据简介 股票实时交易数据涵盖股票价格、成交量、涨跌幅等多类信息。其在股票交易中极为关键&#xff0c;高速准确的数据对各方意义重大。投资者可借此及时捕捉机会、优化策略与降低风险&#xff1b;实时准确的实时交易数据是股票市场有效运转的核心要素之一。 使用…...

【C++】动态内存与智能指针——shared_ptr 和 new 结合使用

12.1.3 shared_ptr 和 new 结合使用 如上文所述&#xff0c;如果我们不初始化一个智能指针&#xff0c;那么它将会被初始化为一个空指针&#xff08;需要注意的是&#xff0c;智能指针与普通指针在此处有着非常明显的区别。如果只声明某个类型的普通指针&#xff0c;而不对它进…...

遥感数据集:FTW全球农田边界和对应影像数据,约160万田块边界及7万多个样本

Fields of The World (FTW) 是一个面向农业田地边界实例分割的基准数据集&#xff0c;旨在推动机器学习模型的发展&#xff0c;满足全球农业监测对高精度、可扩展的田地边界数据的需求。该数据集由kerner-lab提供&#xff0c;于2024年8月28日发布&#xff0c;主要特征包括&…...

马斯克的 AI 游戏工作室:人工智能与游戏产业的融合新纪元

近日&#xff0c;马斯克在 X 平台&#xff08;前身为 Twitter&#xff09;发文称&#xff0c;“太多游戏工作室被大型企业所拥有&#xff0c;xAI 将启动一个 AI 游戏工作室&#xff0c;让游戏再次变得精彩”。这一言论不仅展示了马斯克对游戏行业现状的不满&#xff0c;也揭示了…...

农安县建设局官方网站/开发一个app软件多少钱

决策树算法ID3和C4.5实现鸾尾花分类预测ID3和C4.5算法原理简单介绍1、这两个算法差别不是特别大&#xff0c;一个是用信息增益来判断&#xff0c;一个是用信息增益率来判断&#xff0c;在sklearn库中指定 criterion“entropy” 即可&#xff0c;只是准确度不一样。2、这两个算法…...

.net网站开发优点/搜索引擎优化seo论文

js 数组去重 记得js 数组去重3种方法&#xff1a; for 循环两次 使用 Array.prototype.indexOf[注意这个方法是 es5 的&#xff0c;兼容性] 使用 对象的键具有唯一性的这一特性&#xff0c;其实在python中的 sets key 也是具有唯一性的 // 使用第三种方法实现的兼容性处理&…...

做机械配件的网站/全网营销推广软件

上下文切换&#xff08;Context Switch&#xff09;&#xff0c;也称为PCB&#xff0c;性质为环境切换。上下文切换&#xff0c;有时也称做进程切换或任务切换&#xff0c;是指CPU 从一个进程或线程切换到另一个进程或线程。中文名上下文切换外文名Context Switch性质切换进程控…...

上海单位建设报建网站/网站文章优化技巧

在家装设计当中&#xff0c;卫生间的设计非常重要&#xff0c;因为它和我们联系十分紧密&#xff0c;而且使用也极其频繁&#xff0c;如果设计不过关的话&#xff0c;会极大降低我们的日常体验&#xff0c;在设计卫生间的时候&#xff0c;卫浴产品选择非常关键&#xff0c;因为…...

东莞建设网站推广公司地址/各种推广平台

http://blog.csdn.net/jay14/article/details/54074553 TLB原理 转载于:https://www.cnblogs.com/wangdgy/p/8465574.html...

郑州网站seo技术/盐城网站优化

ADSL线路上传与下载速度之间关系ADSL上传速度对下载的影响--------------------------------------------------------------------------------------TCP/IP规定&#xff0c;每一个封包&#xff0c;都需要有acknowledge讯息的回传&#xff0c;也就是说&#xff0c;传输的资料&…...