SQL慢的原因

读操作慢

在大部分的项目中,对于数据库的读操作是要比写操作多的,所以首先来谈一下读操作慢的原因。
如何定位慢SQL
MySQL中有慢查询日志,默认是关闭的,需要手动打开。
1.查询慢日志是否开启

mysql> show variables like '%slow_query_log%';

OFF 为关闭 ON为开启
2.开启慢查询日志

mysql> set global slow_query_log='ON';

这种方式只对当前数据库生效,MySQL重启后则会失效。如果要永久生效,就必须修改配置文件my.cnf
3.永久开启慢查询日志
my.cnf中找到[mysqld],在其下面添加如下代码即可

slow_query_log=ON
slow_query_log_file=/usr/local/mysql/var/localhost-slow.log
long_query_time=5
log-queries-not-using-indexes = 1

配置好后,需重启mysql服务
相关参数说明
1.slow_query_log
该配置项是决定是否开启慢日志查询功能,配置的值有ON或者OFF
2.slow_query_log_file
该配置项是慢日志查询的记录文件,需要手动创建
3.long_query_time
该配置项是设置慢日志查询的时间阈值,当超过这个阈值时,慢日志才会被记录.配置的值有0(任何的sql语句都记录下来),或者>0(具体的阈值).该配置项是以秒为单位的,并且可以设置为小数
4.log-queries-not-using-indexes
该配置项是为了记录未使用到索引的sql语句
读操作慢的原因
一.未命中索引
可以通过在所执行的SQL前加上explain来分析当前 SQL 的执行计划。
在这里插入图片描述
1.type

表示 MySQL 在表中找到所需行的方式。其中常用的类型有:ALL、index、range、ref、eq_ref、const、system、NULL,这些类型从左到右,性能逐渐变好。

ALL:Mysql 遍历全表来找到匹配的行;

index:与 ALL 区别为 index 类型只遍历索引树;

range:只检索给定范围的行,使用一个索引来选择行;

ref:表示上述表的连接匹配条件,哪些列或常量被用于查找索引列上的值;

eq_ref:类似ref,区别在于使用的是否为唯一索引。对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用 primary key 或者 unique key 作为关联条件;

const、system:当 Mysql 对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于 where 列表中,Mysql 就能将该查询转换为一个常量,system 是 const 类型的特例,当查询的表只有一行的情况下,使用 system;

NULL:Mysql 在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

2.possible_keys

查询时可能使用到的索引(但不一定会被使用,没有任何索引时显示为 NULL)。

3.key

实际使用到的索引。

4.rows

估算查找到对应的记录所需要的行数。

5.Extra

比较常见的是下面几种:

Using index:表明使用了覆盖索引,无需进行回表;

Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示 mysql 服务器将在存储引擎检索行后再进行过滤;

Using temporary:表示 MySQL 需要使用临时表来存储结果集,常见于排序和分组查询,常见 group by,order by;

Using filesort:当 Query 中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”。

二.脏页问题
内存数据页和磁盘数据页不一致时,那么称这个内存数据页为脏页。
为了避免每次在读写数据时访问磁盘增加 IO 开销,Innodb 存储引擎通过把相应的数据页和索引页加载到内存的缓冲池(buffer pool)中来提高读写速度。然后按照最近最少使用原则来保留缓冲池中的缓存数据。当要读入的数据页不在内存中时,就需要到缓冲池中申请一个数据页,但缓冲池中数据页是一定的,当数据页达到上限时此时就需要把最久不使用的数据页从内存中淘汰掉。但如果淘汰的是脏页呢,那么就需要把脏页刷到磁盘里才能进行复用。
对于刷脏页的情况,我们需要控制脏页的比例,不要让它经常接近 75%。同时还要控制 redo log 的写盘速度,并且通过设置 innodb_io_capacity 参数告诉 InnoDB 你的磁盘能力。

写操作慢

一.刷脏页
在写操作的时候,存储引擎(Innodb)会将记录写入到 redo log (存储物理日志)中,并更新缓存,这样更新操作就算完成了。后续操作存储引擎会在适当的时候把操作记录同步到磁盘里。写 redo log 的过程是顺序写磁盘的,磁盘顺序写减少了寻道等时间,速度比随机写要快很多( 类似Kafka存储原理),因此写 redo log 速度是很快的。在高并发场景下,redo log 很快被写满了,但是数据来不及同步到磁盘里,这时候就会产生脏页,并且还会阻塞后续的写入操作,SQL 执行自然会变慢。

二.锁
Mysql 中,当某一条 SQL 所要更改的行刚好被加了锁,那么此时只有等锁释放了后才能进行后续操作。
查看当前锁情况:

SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;

事务如果等待时间过长或出现死锁的情况,可以通过「kill 线程ID(trx_mysql_thread_id)」 的方式释放当前的锁。

猜你喜欢

转载自blog.csdn.net/weixin_43278644/article/details/112697819