mysql之慢SQL优化,优化器的反复横跳,不走索引

sql如下:

SELECT *
FROM user
WHERE is_deleted = 'N'
  AND transaction_type IN (232, 330)
  AND gmt_created >= '2025-01-15 00:00:00'
  AND gmt_created < '2025-02-15 00:00:00';

index 情况,gmt_created存在索引,
执行计划分析如下:

{
  "type": "ALL",         // 全表扫描(最差访问方式)
  "possible_keys": "gmt_created", 
  "key": null,           // 实际未使用索引
  "rows": 2,681,650,     // 扫描268万行
  "filtered": 0.41,      // 仅0.41%数据符合条件
  "Extra": "Using where" // 需逐行过滤数据
}

很奇怪,为啥不走gmt_created这个索引,而且有时候过一会,优化器又走了索引,但是大部分都是走全标扫描

大佬们,这么什么情况,优化器反复横跳?

3 Likes

你把其他 2 个条件去掉,看是不是走索引,是其他 2 个条件导致的吧。

1 Like
{
    "select_type": "SIMPLE",
    "partitions": null,
    "type": "ALL",
    "possible_keys": "gmt_created",
    "key": null,
    "key_len": null,
    "ref": null,
    "rows": 2113132,
    "filtered": 17.78,
    "Extra": "Using where"
}

一样,不好用,很奇怪,索引区分度也是有的,符合条件的数据仅仅占比,17.78%

1 Like

记一次Mysql不走日期字段索引的原因_mysql日期条件不走索引-CSDN博客
我给忘记了。类似 in 也有数据量问题,在一定范围内走索引,一定范围内走全表。

2 Likes

对,和结果集合数据量有很大关系,符合条件的数据基本占比在10%到15%左右,而且原始SQL,in的条件是没有索引,去掉了也是不走索引,想让走索引,只能force index了

1 Like

你是单字段建立的索引?换联合索引试试啊!

1 Like

对的,联合的也不好用,尝试了一下

1 Like

目前查询的资料,感觉这个很有道理,涉及到随机IO和顺序IO:
目前有效数据占比在15%到35%之间,因为如果走了gmt_created 索引,就要走id回表查询,因为是按照gmt_created 排序来的,id是无序的,回表就是一个随机磁盘IO,随机IO的耗时远远大于顺序IO的耗时,如果走全标扫描就是一个顺序IO,优化器认为全表的顺序IO优于大批量的随机IO

1 Like

看看你的表有多少数据,数据量太少的话,全表扫表比走索引更快

1 Like

索引扫描成本=索引IO成本+回表IO成本+过滤CPU成本>全表扫描成本

1 Like

在那个时间范围内的数据占比多少?

1 Like

占比接近15%到20%左右

1 Like

看你这个 transaction_type,类型都200了,是不是有200多种类型? 有的话,可以在这里建一个索引

1 Like

transaction_type 是交易类型吧?交易类型应该不会有200多种吧

1 Like

可以尝试一下 force index 强制走索引,看看慢不慢

1 Like

走in了,少量的in条件会直接走这个,大概100条以上才会走其他索引。或者你用联合索引试一下

1 Like

通俗点讲,你2个in条件,在优化器看来就是固定的条件,固定的肯定是优于你下面的时间范围的,而大量的in条件,这分散一个,那分散一个反而又不如范围条件了

1 Like

走强制索引没有问题

1 Like

不会,就6种

1 Like

听腾讯数据库大佬说,mysql 8 的话 IN 在 1000 以下的都问题不大

2 Likes