mysql索引执行要多久完成_明明我建了索引,为什么sql执行的还是这么慢?

很多同学经常遇到这样一个问题,就是为了避免sql 执行缓慢,提前将各种可能用到的字段都添加上索引,查询的时候尽可能的使用这些字段,避免全表扫描。可是,明明我已经添加了索引,问什么还是这么慢呢?

一条 SQL 语句执行的很慢,那是每次执行都很慢呢?还是大多数情况下是正常的,偶尔出现很慢呢?所以我觉得,我们还得分以下两种情况来讨论。大多数情况是正常的,只是偶尔会出现很慢的情况。

在数据量不变的情况下,这条SQL语句一直以来都执行的很慢。

针对这两种情况,我们来分析下可能是哪些原因导致的。

一、针对偶尔很慢的情况

一条 SQL 大多数情况正常,偶尔才能出现很慢的情况,针对这种情况,我觉得这条SQL语句的书写本身是没什么问题的,而是其他原因导致的,那会是什么原因呢?

1、数据库在刷新脏页

当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。

2、拿不到锁

这个就比较容易想到了,我们要执行的这条语句,刚好这条语句涉及到的表,别人在用,并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。或者,表没有加锁,但要使用到的某个一行被加锁了,这个时候,我也没办法啊。

下来我们来访分析下第二种情况,我觉得第二种情况的分析才是最重要的。

二、针对一直都这么慢的情况

我们先来假设我们有一个表,表里有下面两个字段,分别是主键 id,和两个普通字段 c 和 d。并建立相关索引。

mysql> CREATE TABLE `t` (

`id` int(11) NOT ,

`c` int(11) DEFAULT ,

`d` int(11) DEFAULT ,

PRIMARY KEY (`id`)

) ENGINE=InnoDB;

1、没用到索引

没有用上索引,我觉得这个原因是很多人都能想到的,例如你要查询这条语句:

select * from t where 100

1)字段有索引,但却没有用索引

好吧,这个时候你给 c 这个字段加上了索引,然后又查询了一条语句:

select * from t where c - 1 = 1000;

3)函数操作导致没有用上索引

如果我们在查询的时候,对字段进行了函数操作,也是会导致没有用上索引的,例如:

select * from t where pow(c,2) = 1000;

2、数据库自己选错索引

我们在进行查询操作的时候,例如:

select * from t where 100 < c and c < 100000;

就算你在 c 字段上有索引,系统也并不一定会走 c 这个字段上的索引,而是有可能会直接扫描扫描全表,找出所有符合 100 < c and c < 100000 的数据。

为什么会这样呢?系统是有可能走全表扫描而不走索引的。

那系统是怎么判断呢?

判断来源于系统的预测,也就是说,如果要走 c 字段索引的话,系统会预测走 c 字段索引大概需要扫描多少行。如果预测到要扫描的行数很多,它可能就不走索引而直接扫描全表了。

那么问题来了,系统是怎么预测判断的呢?这里我给你讲下系统是怎么判断的吧,虽然这个时候我已经写到脖子有点酸了。

系统是通过索引的区分度来判断的,一个索引上不同的值越多,意味着出现相同数值的索引越少,意味着索引的区分度越高。我们也把区分度称之为基数,即区分度越高,基数越大。所以呢,基数越大,意味着符合 100 < c and c < 10000 这个条件的行数越少。

所以呢,一个索引的基数越大,意味着走索引查询越有优势。

三、总结

建了索引,并且使用了索引字段,并不代表着查询一定走索引。sql 执行缓慢存在多种可能,具体问题具体分析吧。添加索引,慎用函数,根据规则避免走全表扫描。优化是一个过程,需要慢慢琢磨。

ps:看更多干货,加入技术交流微信群可以关注我的公众号360linker

你可能感兴趣的:(mysql索引执行要多久完成)