如何通过 explain 判断使用二级索引之后,是否还存在回表操作?

表结构

-- crawler2.keywordtask definition

CREATE TABLE `keywordtask` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `keyword` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `nums` int NOT NULL,
  `start_date` datetime DEFAULT NULL,
  `skip_filter` tinyint DEFAULT NULL,
  `priority` tinyint DEFAULT NULL,
  `track_source_id` int DEFAULT NULL,
  `company_id` int DEFAULT NULL,
  `meta_uuid` varchar(100) DEFAULT NULL,
  `len_parse_result_list` mediumint DEFAULT NULL,
  `push_uuid` varchar(64) DEFAULT NULL COMMENT '用于表示推送批次',
  `parser` varchar(32) DEFAULT NULL,
  `sorting_method` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `keywordtask_company_id_index` (`company_id`),
  KEY `idx_updated_at` (`updated_at`),
  KEY `index_meta_uuid` (`meta_uuid`),
  KEY `idx_created_at` (`created_at`),
  KEY `keywordtask_push_uuid_IDX` (`push_uuid`) USING BTREE,
  KEY `idx_track_source_id_created_at_len_parse_result_list` (`track_source_id`,`created_at`,`len_parse_result_list`)
) ENGINE=InnoDB AUTO_INCREMENT=283001480 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

查询的 sql

SELECT
    track_source_id,
    DATE_FORMAT(created_at, '%Y-%m-%d') AS day,
    COUNT(*) AS total_count,
    SUM(CASE WHEN len_parse_result_list = 0 THEN 1 ELSE 0 END) AS len_parse_result_list_zero_count,
    SUM(CASE WHEN len_parse_result_list IS NULL THEN 1 ELSE 0 END) AS len_parse_result_list_null_count,
    SUM(CASE WHEN len_parse_result_list > 0 THEN 1 ELSE 0 END) AS len_parse_result_list_gte_zero_count
FROM
    keywordtask
WHERE
    created_at >= NOW() - INTERVAL 30 DAY
GROUP BY
    track_source_id,
    day
ORDER BY
    track_source_id,
    day;

使用 explain 分析的结果

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEkeywordtask indexidx_created_at,idx_track_source_id_created_at_len_parse_result_listidx_track_source_id_created_at_len_parse_result_list14 13432415450.0Using where; Using index; Using temporary; Using filesort

我想知道的是,这个查询 sql 还存在「回表」吗? 以及是怎么判断的?

我觉得 mysql 设计的如果完善的话,是不应该回表的,因为查询 sql 需要的所有字段都在这个 idx_track_source_id_created_at_len_parse_result_list 二级索引中了。但是又担心 mysql 设计不完善,看到 created_at >= NOW() - INTERVAL 30 DAY 就不用后面的 len_parse_result_list

可以通过 explain 输出的 key_len 字段判断吗?

阅读 1.2k
avatarAI BotBETA

这个查询 sql 不存在「回表」操作。

在 MySQL 中,是否发生回表操作可以通过 EXPLAIN 命令的输出中的几个字段来判断,主要是 key 字段(表明实际使用的索引)和 Extra 字段(包含额外的执行信息)。

在你的查询中,EXPLAIN 的输出显示 key 字段为 idx_track_source_id_created_at_len_parse_result_list,这表示 MySQL 选择了这个复合索引来执行查询。重要的是,查询中使用的字段 track_source_idcreated_atlen_parse_result_list 都在这个索引中。

Extra 字段中的 Using index 表示 MySQL 能够在索引中直接找到所有需要的数据,而不需要回表访问原始表中的数据行。这是因为查询中涉及的所有列(包括在 SELECT 列表、WHERE 子句、GROUP BY 子句和聚合函数中使用的列)都包含在索引中。

因此,你可以确信这个查询没有发生回表操作,MySQL 充分利用了索引来高效地执行查询。

key_len 字段虽然可以显示索引中使用的最长部分的长度,但它通常不是直接用来判断是否存在回表操作的直接依据。key_len 更多是用于理解索引中哪些部分被实际使用,以及索引的存储效率等方面。在你的情况下,key_len 的值表明了索引中 track_source_idcreated_atlen_parse_result_list 这部分被使用,但这并不直接说明是否回表,而是需要结合 Extra 字段中的信息来综合判断。

2 个回答

你可以根据 Extra 来判断 一般判断是否回表可以这样
1、出现了Using Index表示出现索引覆盖,不需要回表;
2、出现了Using Index Condition表示查找使用了索引,不需要回表查询,因为要过滤的字段在索引中。
3、Extra中是using index & using where,表示select的数据在索引中能找到,但需要根据where条件过滤,这种情况也不回表。
4、在使用到了索引,且Extra是Using where的情况下,才代表回表查询数据。
5、主键查询不回表,因为需要字段就是从聚簇索引上查找,不需要回表,但是Extra看不出来。

看着没有回表,你可以看看你的key_len 是否包含了所有查询字段的长度。

推荐问题
宣传栏