首页 > 解决方案 > 为什么Mysql对单个表使用索引,但在连接时不使用

问题描述

我想知道为什么 mysql 将索引用于单个表查询,而不用于连接查询,即使我强制使用索引。

只需显示表和查询:

show create table dc_assess_plan_batch;
CREATE TABLE `dc_assess_plan_batch` (
   `id` varchar(255) NOT NULL,
   `app_batch_id` varchar(255) NOT NULL COMMENT '数据来源的id ',
   `project_id` varchar(255) NOT NULL COMMENT '课程计划id',
   `name` varchar(32) DEFAULT NULL COMMENT '批次名',
   `time` datetime DEFAULT NULL COMMENT '批次的时间',
   `batch_id` varchar(255) DEFAULT NULL,
   `status` tinyint(4) DEFAULT NULL COMMENT '1.可用关系.0 不可用',
   `app_from` varchar(10) DEFAULT NULL COMMENT '数据来源',
   PRIMARY KEY (`id`),
   KEY `inx_project_id` (`project_id`) USING BTREE,
   KEY `app_batch_id` (`app_batch_id`) USING BTREE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `dc_assess_task` (
   `id` varchar(255) NOT NULL,
   `name` varchar(255) DEFAULT NULL COMMENT '任务名称',
   `class_id` varchar(255) DEFAULT NULL COMMENT '班级id',
   `course_id` varchar(255) DEFAULT NULL COMMENT '课程id',
   `app_from` varchar(255) DEFAULT NULL COMMENT '成绩来源',
   `term_id` varchar(255) DEFAULT NULL COMMENT '学期id',
   `publish_time` datetime DEFAULT NULL COMMENT '任务发布时间',
   `completion_degree` double(10,3) DEFAULT NULL COMMENT '完成度',
   `course_name` varchar(255) DEFAULT NULL COMMENT '课程名称',
   `school_id` varchar(255) DEFAULT NULL,
   `app_batch_id` varchar(255) NOT NULL,
   `score_type` varchar(10) DEFAULT NULL COMMENT '''成绩计算规则 COUNT :按数量,  SCORE:按照分数, KCBCOUNT:按课程币数量'',',
   `xxpj_mode` enum('BY_GROUP','BY_PERSON') DEFAULT NULL COMMENT '线下评价评分模式',
   `upload_flag` tinyint(4) NOT NULL DEFAULT '0' COMMENT '标志任务是否线下上传,1是,0否',
   PRIMARY KEY (`id`),
   KEY `FKrx8fxs12oe1mafttciiwir6cm` (`app_from`) USING BTREE,
   KEY `app_batch_id` (`app_batch_id`) USING BTREE
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

有两个表,并且都在归档的“app_batch_id”上有索引

explain select * from dc_assess_plan_batch where app_batch_id = '2ebb4066038441229e937d2de4a9b5632018-12-07';

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1   SIMPLE  dc_assess_plan_batch    ref app_batch_id    app_batch_id    767 const   1   Using index condition
explain select * from dc_assess_plan_batch dapb join dc_assess_task dat on dapb.app_batch_id = dat.app_batch_id where dat.course_id = '562aecc2d1c64fabbff4a18496acc757';

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1   SIMPLE  dapb    ALL app_batch_id                277947  
1   SIMPLE  dat ref app_batch_id    app_batch_id    767 ifass.dapb.app_batch_id 1   Using where

-查询3

explain select * from dc_assess_plan_batch dapb force index (app_batch_id) join dc_assess_task dat on dapb.app_batch_id = dat.app_batch_id where dat.course_id = '562aecc2d1c64fabbff4a18496acc757';

# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1   SIMPLE  dapb    ALL app_batch_id                277947  
1   SIMPLE  dat ref app_batch_id    app_batch_id    767 ifass.dapb.app_batch_id 1   Using where

为什么'app_batch_id'上的索引在加入时不起作用,甚至强制使用索引

标签: mysqljoinindexing

解决方案


哪个跑得更快?有时“优化器最清楚”。然而,EXPLAINs看起来一样吗?

我希望这些对性能有很大帮助:

dat:  (course_id, app_batch_id)  -- the table has nothing like this
dapb:  (app_batch_id)

当看到 aJOIN时,优化器通常会查看WHERE子句来决定从哪个表开始。但是,唉,没有索引dat.course_id。所以它需要以“蛮力”的方式运行查询——扫描一张表的所有内容,然后进入另一张表。一个强有力的线索ALL .. 277947EXPLAIN. 这表示它无法从dat.

如果它有这样的索引,优化器将从 开始dat,可能会到达 1 行,而不是 277947,然后使用您已有的索引进入另一个表,即使不使用FORCE INDEX


推荐阅读