You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL 8.0.29查询未走索引,全表扫描问题排查求助

MySQL 8.0.29全表扫描未选用索引问题分析

问题场景

使用MySQL 8.0.29版本,执行以下查询时触发全表扫描,未选用已创建的索引,寻求原因及解决方法。

查询语句

select  journey_level, 
        src_screen_name from_entity_name, 
        src_screen_id from_entity_id, 
        dest_screen_name to_entity_name, 
        dest_screen_id to_entity_id, 
        dest_screen_id to_entity_id_list, 
        concat(journey_level, '-', src_screen_id, '-', src_screen_name) from_entity, 
        concat(journey_level + 1, '-', dest_screen_id, '-', dest_screen_name) to_entity, 
        count(1) cnt, 
        sum(ifnull(is_crash, 0)) crash_cnt, 
        sum(ifnull(is_anr, 0)) anr_cnt, 
        sum(ifnull(is_rage, 0)) rage_cnt, 
        case dest_screen_id 
            when -1 
            then 'Red' 
            else '' 
        end node_color 
from ue_summary.user_journey_screens_1943 s 
where first_session_created_at between '2022-09-17 00:00:00' and '2022-10-17 10:42:35' 
and s.platform = '1' 
and journey_level <= '4' 
group by journey_level, 
        from_entity_id, 
        from_entity_name, 
        to_entity_id, 
        to_entity_name;

执行计划

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: s
   partitions: NULL
         type: ALL
possible_keys: date_platform_level,platform_date
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 793512853
     filtered: 1.67
        Extra: Using where; Using temporary

表结构

CREATE TABLE `user_journey_screens_1943` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `app_id` int DEFAULT NULL,
  `platform` tinyint DEFAULT NULL,
  `asi` bigint DEFAULT NULL,
  `first_session_created_at` datetime DEFAULT NULL,
  `user_task_id` bigint DEFAULT NULL,
  `app_version_id` int DEFAULT NULL,
  `journey_level` int DEFAULT NULL,
  `src_screen_id` bigint DEFAULT NULL,
  `src_screen_name` varchar(300) DEFAULT NULL,
  `src_capture_time` bigint DEFAULT NULL,
  `src_capture_time_relative` bigint DEFAULT NULL,
  `dest_screen_id` bigint DEFAULT NULL,
  `dest_screen_name` varchar(300) DEFAULT NULL,
  `dest_capture_time` bigint DEFAULT NULL,
  `dest_capture_time_relative` bigint DEFAULT NULL,
  `is_crash` tinyint DEFAULT NULL,
  `is_anr` tinyint DEFAULT NULL,
  `is_rage` tinyint DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `app_id_date_level` (`app_id`,`first_session_created_at`,`journey_level`),
  KEY `asi` (`asi`),
  KEY `date_platform_level` (`first_session_created_at`,`platform`,`journey_level`),
  KEY `platform_date` (`platform`,`first_session_created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=1937612717 DEFAULT CHARSET=latin1

索引未被选用的原因

  1. 列类型不匹配触发隐式转换
    查询中journey_level <= '4',但表中journey_level是int类型,字符串与数字的比较会触发隐式类型转换,破坏索引的有序性,导致MySQL无法利用索引中journey_level列的过滤能力。

  2. 现有索引覆盖度不足
    现有索引仅包含过滤条件相关的列,但查询需要的分组字段(src_screen_id、src_screen_name等)和聚合计算字段(is_crash、is_anr等)都不在索引中。如果走索引,MySQL需要频繁回表读取这些字段,对于7.9亿行的表来说,回表开销远大于全表扫描,优化器因此放弃使用索引。

  3. 优化器成本预估判断
    执行计划显示filtered仅为1.67%,预估符合条件的行数约1300万,但MySQL认为走索引后回表的总成本高于全表扫描,最终选择全表扫描。

解决方案

  1. 修正类型不匹配问题
    将查询中的journey_level <= '4'改为journey_level <= 4,避免隐式转换,确保索引能正常发挥过滤作用。

  2. 创建覆盖索引
    针对查询的过滤、分组、聚合需求,创建包含所有必要字段的联合索引,让MySQL无需回表即可完成查询:

CREATE INDEX idx_platform_date_level_cover ON ue_summary.user_journey_screens_1943 (
    platform, 
    first_session_created_at, 
    journey_level, 
    src_screen_id, 
    src_screen_name, 
    dest_screen_id, 
    dest_screen_name, 
    is_crash, 
    is_anr, 
    is_rage
);

索引列顺序遵循最左前缀原则:先放等值过滤的platform,再放范围过滤的first_session_created_at,接着是过滤条件journey_level,最后是分组和聚合需要的字段,确保索引覆盖整个查询流程。

  1. 验证索引效果
    创建索引后,执行EXPLAIN查看执行计划,确认type列变为range或ref,key列显示新创建的索引,说明索引已被有效利用。

内容的提问来源于stack exchange,提问作者RRQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:55:48