数据库——慢sql的原因

1.sql语句执行速度慢

sql语句执行速度慢可以分为两种情况进行讨论,

  1. 大多数情况正常,偶尔很慢
  2. 数据量不变,一直很慢

1.1 大多数情况正常,偶尔很慢

:one: 数据库在刷新脏页(flush):worried:
当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。

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

:raising_hand:刷脏页有下面4种场景:

  • :boom: redolog写满了:redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。

  • :boom: 内存不够用了:如果一次查询较多的数据,恰好碰到所查数据页不在内存中时,需要申请内存,而此时恰好内存不足的时候就需要淘汰一部分内存数据页,如果是干净页,就直接释放,如果恰好是脏页就需要刷脏页。

  • MySQL 认为系统“空闲”的时候:这时系统没什么压力。

  • MySQL 正常关闭的时候:这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。

:two:执行sql语句遇到锁!:worried:
:boom:比如并发事务下,执行的sql语句涉及到了表锁和行锁,这种情况就只能等待了,导致sql语句很慢

1.2 数据量不变,一直很慢

如果每次都执行的很慢,应该需要考虑sql语句本身的问题了
假设有以下建表语句:

mysql> CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

:one: 没用上索引:worried:

  • 字段没有索引
    比如你没有在目标字段上加上索引,就只能走全表扫描了,例如下面这行语句,你并没有给字段c加上索引
    select * from t where 100 <c and c < 100000;
  • 字段有索引,但却没有用索引
    下面这行sql语句,虽然你在c上加了索引,但却因为运算操作而没有走索引:
    select * from t where c - 1 < 100000;
    同理这种函数操作也没有用到索引的!
    select * from t where pow(c,10) < 100000;
    还有下面这种联合索引,根据最左匹配原则也没有名中,故只能走全表扫描 :boom:
    ALERT TABLE 't' ADD INDEX 'union_index'('a','b','c');
    select * from t where b < 100 and c = 10;

:two: 数据库选错了索引:worried:

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!