mysql - 为什么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”上有索引
- 查询1:
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
- 查询2
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'上的索引在加入时不起作用,甚至强制使用索引
解决方案
哪个跑得更快?有时“优化器最清楚”。然而,EXPLAINs
看起来一样吗?
我希望这些对性能有很大帮助:
dat: (course_id, app_batch_id) -- the table has nothing like this
dapb: (app_batch_id)
当看到 aJOIN
时,优化器通常会查看WHERE
子句来决定从哪个表开始。但是,唉,没有索引dat.course_id
。所以它需要以“蛮力”的方式运行查询——扫描一张表的所有内容,然后进入另一张表。一个强有力的线索ALL .. 277947
在EXPLAIN
. 这表示它无法从dat
.
如果它有这样的索引,优化器将从 开始dat
,可能会到达 1 行,而不是 277947,然后使用您已有的索引进入另一个表,即使不使用FORCE INDEX
。
推荐阅读
- javascript - 谷歌脚本编辑器 || 不能在 IF 语句中工作
- javascript - 排序匈牙利语词典
- css - CSS:如何使两个网格相等(其中一个在另一个之上)
- python - 修改蛇文件以运行一个工作流的多次迭代
- python - 如何从表单提交中获取输入并使用它来使用 django 显示条目
- amazon-web-services - 云存储中的读/写操作到底是什么?是否可以将多个写入请求合并为一个请求?
- python-3.x - 为 TensorBoard 命名 Keras Tuner Trials 目录
- python - 如何在熊猫数据框中找到重复项?
- opengl-es - 带颜色的 OpenGL DrawArrays
- c# - C# JSON - 具有相同属性的不同类型的多个对象的序列化