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。