mysql - 当我在字段列表中选择非索引字段时,为什么 MySQL 停止使用索引进行连接

标签 mysql performance indexing

我有以下两个表:

CREATE TABLE `temporal_expressions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dated_obj_type` varchar(255) DEFAULT NULL,
`dated_obj_id` int(11) DEFAULT NULL,
`start_date` datetime DEFAULT NULL,
`end_date` datetime DEFAULT NULL,
`start_time` int(11) DEFAULT NULL,
`end_time` int(11) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`lock_version` int(11) NOT NULL DEFAULT '0',
`wday` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `te_search` (`dated_obj_type`,`dated_obj_id`,`start_date`,`end_date`),
KEY `te_calendar`   (`dated_obj_type`,`dated_obj_id`,`start_date`,`end_date`,`start_time`,`end_time`),
KEY `te_search_wday` (`dated_obj_type`,`dated_obj_id`,`start_date`,`end_date`,`wday`),
KEY `te_calendar_wday` (`dated_obj_type`,`dated_obj_id`,`start_date`,`end_date`,`start_time`,`end_time`,`wday`),
KEY `te_index` (`wday`,`dated_obj_type`,`start_date`,`end_date`,`start_time`,`end_time`,`dated_obj_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8162445 DEFAULT CHARSET=latin1

CREATE TABLE `asset_blocks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`block_type` int(11) DEFAULT '0',
`spaces_left` int(11) DEFAULT NULL,
`provider_note` varchar(255) DEFAULT NULL,
`extra_data` text,
`lock_version` int(11) DEFAULT '0',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`service_provider_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`,`id`),
KEY `service_provider_id` (`service_provider_id`,`type`,`id`),
) ENGINE=InnoDB AUTO_INCREMENT=516867 DEFAULT CHARSET=latin1

如果我对此查询运行解释(请注意,我只是从 temporal_expressions 中选择 te_calendar_wday 索引中的字段),它会按预期使用索引进行连接

EXPLAIN SELECT asset_blocks.*, temporal_expressions.id,
temporal_expressions.dated_obj_type, temporal_expressions.dated_obj_id,
temporal_expressions.start_date, temporal_expressions.end_date,
temporal_expressions.start_time
FROM `asset_blocks`
LEFT OUTER JOIN `temporal_expressions`
ON `temporal_expressions`.dated_obj_id = `asset_blocks`.id 
  AND `temporal_expressions`.dated_obj_type = 'AssetBlock'
WHERE ( temporal_expressions.start_date <= '2010-11-25' 
AND temporal_expressions.end_date >= '2010-11-01'
AND temporal_expressions.start_time < 1000 AND temporal_expressions.end_time > 1200 
AND temporal_expressions.wday IN (1,2,3,4,5,6) 
AND asset_blocks.id IN (1,2,3,4,5,6,7,8,9) )

1 SIMPLE temporal_expressions range    te_search,te_calendar,te_search_wday,te_calendar_wday,te_index te_calendar_wday 272 NULL 9 Using where; Using index
1 SIMPLE asset_blocks eq_ref PRIMARY PRIMARY 4 lb_production.temporal_expressions.dated_obj_id 1

但是,如果我运行此查询(请注意,我已将非索引字段添加到字段列表),它不再使用索引(它使用连接缓冲区)。这是故意的还是我遗漏了什么?

EXPLAIN SELECT asset_blocks.*, temporal_expressions.id,
temporal_expressions.dated_obj_type, temporal_expressions.dated_obj_id,
temporal_expressions.start_date, temporal_expressions.end_date,
temporal_expressions.start_time, temporal_expressions.created_at
FROM `asset_blocks`
LEFT OUTER JOIN `temporal_expressions`
ON `temporal_expressions`.dated_obj_id = `asset_blocks`.id 
  AND `temporal_expressions`.dated_obj_type = 'AssetBlock'
WHERE ( temporal_expressions.start_date <= '2010-11-25' 
AND temporal_expressions.end_date >= '2010-11-01'
AND temporal_expressions.start_time < 1000 AND temporal_expressions.end_time > 1200 
AND temporal_expressions.wday IN (1,2,3,4,5,6) 
AND asset_blocks.id IN (1,2,3,4,5,6,7,8,9) )


1 SIMPLE asset_blocks range PRIMARY PRIMARY 4 NULL 9 Using where
1 SIMPLE temporal_expressions range te_search,te_calendar,te_search_wday,te_calendar_wday,new_te_index te_search 272 NULL 9 Using where; Using join buffer

最佳答案

我不确定这里是否是这种情况,但是:

如果只选择索引字段,MySQL 可以从索引中回答整个查询,甚至不加载表数据文件。

如果你选择了一个没有索引的字段,它必须加载表数据。

在制定执行计划时,在某些情况下(见评论)MySQL 决定进行全表扫描,尽管存在索引。这是因为盲目读取所有数据比查找索引中的每个条目然后读取数据要快得多。

关于mysql - 当我在字段列表中选择非索引字段时,为什么 MySQL 停止使用索引进行连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4139581/

相关文章:

mysql - SQL分类

android - 多步骤流程中的单个 Activity 多个 fragment/单独的 Activity ?

mysql - 尽管存在于数据库中,但未找到 Gerrit 评论

mysql - Hibernate:字段 'id' 没有默认值

mysql - 将多行转换为列

c - 从正弦查找表计算 arcsin 的效率

python - 如何使用 Python 实现最大写入速度?

indexing - Solr Schemaless 模式将字段创建为多值

arrays - 为什么在 Matlab 中通过 sub2ind 进行索引与通过 A(i, j) 进行索引不同?

mysql - Laravel 5.6 - 不支持 ALGORITHM=COPY