I wonder why mysql use index for a single table query, while not for a join query, even i force using index.
Just show the tables and querys:
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;
There are two tables, and both have index on filed 'app_batch_id'
- query1:
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
- query2
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
-query3
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
Why index on 'app_batch_id' not work when join, even force using index
Which runs faster? Sometimes the "Optimizer knows best". However, the EXPLAINs
seem the same?
I would expect these to help significantly with performance:
dat: (course_id, app_batch_id) -- the table has nothing like this
dapb: (app_batch_id)
When seeing a JOIN
, the Optimizer usually looks at the WHERE
clause to decide which table to start with. But, alas, there is no index for dat.course_id
. SO it needs to run the query in a "brute force" way -- Scan all of one table, then reach into the other. A strong clue of this is ALL .. 277947
in the EXPLAIN
. That says that it could not benefit from an index on dat
.
If it had such an index, the Optimizer would start with dat
, reach in for perhaps 1 row, not 277947, then reach into the other table using the index you already have, even without using FORCE INDEX
.