Sunskey

日拱一卒,不期而至

0%

SQL慢的原因和解决办法

SQL执行过慢的原因

1.查询长时间不返回

  • 等待MDL锁

mysql> select * from t where id=1;

一般是表t被锁住了。可以利用show processlist看看语句处于什么状态。

如果是Waiting for table metadata lock的示意图,则表示有一个线程正在表t上请求或者持有MDL写锁。

通过查询sys.schema_table_lock_waits这张表,我们可以直接找到阻塞进程的id,然后把这个链接kill掉。

  • 等flush

有一个线程正要对表t做flush操作,MySQL里面对表做flush操作的用法。

flush tables t with read lock;

flush tables with read lock;

这个两个flush语句,如果制定表 t 的话,代表的只关闭表t,如果没有指定具体的表名,则表示关闭MySQL里所有打开的表。

所以出现Waiting for table flush 状态的可能情况是:有一个命令被别的语句堵住,然后它有堵住了我们select的语句。

  • 等行锁

如果一个事务在这行记录上面上持有一个写锁,那么我们的select 语句就会被堵住。

可以通过sys.innodb_lock_waits表查到。

2.查询慢

1.没有索引

2.为了一致性读,undo log日志过长导致的,判断是不是有长事务。

SQL为什么突然变“慢”

当内存数据页和磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘的数据页的内容就一直了,称为“干净页”。刷新脏页的过程为称为flush。

flush的4种场景

1.对于InnoDB 的redo log写满了。

2.对应的系统内存不足。在需要新的内存页,而内存不够用的时候,就要淘汰一些数据页,空出内存给别的数据页使用。如果淘汰的时“脏页”,则先写入磁盘。

3.MySQL会合理的安排时间,见缝插针的刷新“脏页”。

4.MySQL重启的时候。

刷新脏页虽然时常态,但都是明显影响性能的。

1.一个查询要淘汰的脏页过多,会导致查询的响应时间明显变长。

2.日志写满,更新性能全部堵住,写性能跌为0,这种情况对敏感的业务来说,不能接受。

InnoDB刷新脏页的控制策略

1.调用fio工具,来正确设置innodb_io_capacity的这个参数

Innodb的刷盘速度主要考虑两个因素:一个脏页比例,一个是redo log写盘速度。

合理设置innodb_io_capacity的值,并且多关注脏页比例,**不要让它接近75%**。

脏页的比例是通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的

其中innodb_flush_neighbors 参数为1会顺带把邻居的脏页同步刷新,适用于机械硬盘的场景。5.8以后默认

innodb_flush_neighbors 为0。