mysql数据检索过多导致索引没有生效的问题

查询的时候,在数据量过多时出现索引失效的情况,请问是什么原因?

具体情况,mysql版本5.7.7,ad_stat_day表总数据在250W左右,day_time字段上有建立索引
-- 25号至30号总数据
mysql> select count(*) from ad_stat_day where dayTime BETWEEN  '2017-10-25' and '2017-10-30';
+----------+
| count(*) |
+----------+
|   107063 |
+----------+
1 row in set
-- 只查id的情况下会走索引
mysql> EXPLAIN select id from ad_stat_day where dayTime BETWEEN  '2017-10-25' and '2017-10-30';
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+
| id | select_type | table       | partitions | type  | possible_keys | key         | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | ad_stat_day | NULL       | range | nk_day_time   | nk_day_time | 4       | NULL | 189566 |      100 | Using where; Using index |
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+--------------------------+
1 row in set
-- 查id,fee就不走索引了
mysql> EXPLAIN select id,fee from ad_stat_day where dayTime BETWEEN  '2017-10-25' and '2017-10-30';
+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table       | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | ad_stat_day | NULL       | ALL  | nk_day_time   | NULL | NULL    | NULL | 646016 |    27.18 | Using where |
+----+-------------+-------------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set
--缩小条件范围,查询id,fee也会走索引
mysql> EXPLAIN select id,fee from ad_stat_day where dayTime BETWEEN  '2017-10-27' and '2017-10-30';
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+
| id | select_type | table       | partitions | type  | possible_keys | key         | key_len | ref  | rows   | filtered | Extra                            |
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+
|  1 | SIMPLE      | ad_stat_day | NULL       | range | nk_day_time   | nk_day_time | 4       | NULL | 124092 |      100 | Using index condition; Using MRR |
+----+-------------+-------------+------------+-------+---------------+-------------+---------+------+--------+----------+----------------------------------+
1 row in set

求大佬告知下mysql是根据什么情况来选择使用索引和不使用索引的?

这次范围扫描数据(189566行)不到表总数的10%,而加上一个字段就成了(646016行)占到表总数的25%来了,这个646016行数据mysql是怎么算出来的?还有mysql有明确的配置来说明超过某个阀值(百分比)就不使用索引了吗?
阅读 9.7k
3 个回答

索引:hi,MySQL,这次我给你带来了一个很大范围的索引片哦,并且我的索引结构上面还有一个只在表结构里面存在的数据,你看看怎么查询起来快吧...
MySQL:我擦,你的数据量太大了,我还不如直接去表里面查快呢...


索引:hi,MySQL,我为上次的事情道歉,这次虽然给你带来的范围还是比较大,但是呢,我需要的字段都在我的索引结构上面,你帮我处理一下吧...
MySQL:嗯,这次你不需要通过表结构,我就直接在你自己身上给你处理吧...


上文中的MySQL就是我们知道的MySQL的优化器在处理,《数据库索引结构和设计》这本书中有讲一个三星索引的概念,像你遇到的这种情况,你可以考虑一下是否需要建立一个<day_time , fee>的联合索引,不知道我是否有阐述清楚。

首先你要了解mysql innodb普通索引是由索引列+主键信息组成的,且mysql的检索遵循的最基本的原则就是代价评估策略(瞎起的名,便于理解),就是我怎么能更省时省力的找到你要的结果我就怎么查。
那你这里是三种情况:
1、只查id,明显了,直接查索引就好了
2&3、不止查id,还要fee,那最终肯定要去查表结构了,那看看是查完索引找到这些行的主键数据,再通过主键数据到表里去找到对应的数据行找到fee的代价小,还是不查索引,直接去从头到尾检索表数据来得快。
对2来说,时间段有点长嘛,查了一大块索引再去查表数据太慢了,那就直接从头到尾查表数据吧,ok,不走索引了
对3来说,时间段够短了,我只要查一小部分索引找到一小部分主键数据,再直接根据这些主键信息找到fee就好了

建立id与fee的复合索引。

推荐问题