mysql,优化SQL语句,慢日志分析 SQL mysql



一.分析MySQL服务器当前的状态信息

SHOW SESSION STATUS;

---当前会话下所有语句类型的执行次数

SHOW SESSION STATUS LIKE 'Com_%' ;

---可以了解当前应用是以插入更新为主,还是以查询操作为主,以及各种SQL类型的执行比例大概是多少

SHOW SESSION STATUS LIKE 'InnoDB_rows%';


二.定位执行效率比较低的SQL语句

1.慢查询日志

---查看当前慢查询日志功能是否开启

SHOW VARIABLES LIKE '%slow_query_log%';

---默认为10秒,超过会被记录到日志文件

SHOW VARIABLES LIKE '%slow_query_time%' ;

---测试慢查询日志功能

select SLEEP(11),first_name FROM actor where actor_id = 1; //语句会睡眠11秒


2.查看执行中的任务

---显示当前执行中的SQL语句

SHOW PROCESSLIST;

---睡眠100秒

select SLEEP(100),first_name FROM actor where actor_id = 1; 


3.通过Desc或者Explain命令查看计划执行

-通过慢查询日志中获取到慢的SQL中,通过语句查看执行计划

-两条语句的执行结构是一样的

DESC SELECT * FROM film_actor WHERE film_id = 1;

EXPLAIN SELECT * FROM film_actor WHERE film_id = 1;


KEY

含义

type

表的扫描类型

possible_keys

可能用到的索引

key

实际用到的索引

key_leng

索引的长度

rows

得到结果所需要的查询的行数


三.最后确定问题并采取相应的优化措施#


# 慢查询分析

---开启profiling看到流程慢在哪

set profiling=ON;
show variables like 'profiling';

-然后正常执行sql语句

-这些SQL语句的执行时间都会被记录下来,此时你想查看有哪些语句被记录下来

show profiles;

| Query_ID | Duration   | Query                                             |

+----------+------------+---------------------------------------------------+

|        1 | 0.06811025 | select * from user where age>=60  

|        2 | 0.00151375 | select * from user where gender = 2 and age = 80

-关注下上面的query_id,比如select * from user where age>=60对应的query_id是1,如果你想查看这条SQL语句的具体耗时,那么可以执行以下的命令

show profile for query 1;

| Sending data         | 0.067701 |

-看出Sending data的耗时最大,这个是指执行器开始查询数据并将数据发送给客户端的耗时,因为我的这张表符合条件的数据有好几万条,所以这块耗时最大,也符合预期。

explain SQL

explain select * from user where age>=60 分析一下


# 走了索引还是很慢

第一种是索引区分度太低,比如网页全路径的url链接,这拿来做索引,一眼看过去全都是同一个域名,如果前缀索引的长度建得不够长,那这走索引跟走全表扫描似的,正确姿势是尽量让索引的区分度更高,比如域名去掉,只拿后面URI部分去做索引。

第二种是索引中匹配到的数据太大,这时候需要关注的是explain里的rows字段了。

它是用于预估这个查询语句需要查的行数的,它不一定完全准确,但可以体现个大概量级。

当它很大时,一般常见的是下面几种情况。

如果这个字段具有唯一的属性,比如电话号码等,一般是不应该有大量重复的,那可能是你代码逻辑出现了大量重复插入的操作,你需要检查下代码逻辑,或者需要加个唯一索引限制下。

如果这个字段下的数据就是会很大,是否需要全部拿?如果不需要,加个limit限制下。如果确实要拿全部,那也不能一次性全拿,今天你数据量小,可能一次取一两万都没啥压力,万一哪天涨到了十万级别,那一次性取就有点吃不消了。你可能需要分批次取,具体操作是先用order by id排序一下,拿到一批数据后取最大id作为下次取数据的起始位置。


# 连接数过小, 受数据库和客户端两侧同时限制

# 数据库连接数过小

show variables like 'max_connections';

set global max_connections= 500;

# 应用侧连接数过小

# buffer pool太小,  128Mb -> 512Mb

show global variables like 'innodb_buffer_pool_size';

set global innodb_buffer_pool_size = 536870912;

# buffer pool的缓存命中率

show status like 'Innodb_buffer_pool_%';

Innodb_buffer_pool_read_requests表示读请求的次数。

Innodb_buffer_pool_reads 表示从物理磁盘中读取数据的请求次数。

buffer pool 命中率 = 1 - (Innodb_buffer_pool_reads/Innodb_buffer_pool_read_requests) * 100%

-一般情况下buffer pool命中率都在99%以上,如果低于这个值,才需要考虑加大innodb buffer pool的大小。


签名:这个人很懒,什么也没有留下!
最新回复 (0)
返回