首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >选择外键时在mysql SELECT中找不到索引

选择外键时在mysql SELECT中找不到索引
EN

Stack Overflow用户
提问于 2014-07-10 04:49:53
回答 2查看 163关注 0票数 1

如果我在我的表中选择了一个非外键的列,我会找到索引:

代码语言:javascript
复制
mysql> explain SELECT id FROM stats_image_optimization_hourly WHERE stats_image_optimization_hourly.record_status=1;

+----+-------------+---------------------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
| id | select_type | table                           | type  | possible_keys | key                       | key_len | ref  | rows    | Extra                    |
+----+-------------+---------------------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
|  1 | SIMPLE      | stats_image_optimization_hourly | index | NULL          | image_time_record_status3 | 9       | NULL | 1824413 | Using where; Using index |
+----+-------------+---------------------------------+-------+---------------+---------------------------+---------+------+---------+--------------------------+
1 row in set (0.00 sec)

另一方面,如果选择作为外键的列,则找不到索引:

代码语言:javascript
复制
mysql> explain SELECT server_id FROM stats_image_optimization_hourly WHERE stats_image_optimization_hourly.record_status=1;

+----+-------------+---------------------------------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table                           | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+----+-------------+---------------------------------+------+---------------+------+---------+------+---------+-------------+
|  1 | SIMPLE      | stats_image_optimization_hourly | ALL  | NULL          | NULL | NULL    | NULL | 1824413 | Using where |
+----+-------------+---------------------------------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

下面是表的定义:

代码语言:javascript
复制
stats_image_optimization_hourly | CREATE TABLE `stats_image_optimization_hourly` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `time_stamp` datetime NOT NULL,
  `site_id` int(11) NOT NULL,
  `server_id` int(11) NOT NULL,
  `device_class_id` int(11) NOT NULL,
  `congestion_level_id` int(11) NOT NULL,
  `network_type_id` int(11) NOT NULL,
  `image_format_id` int(11) NOT NULL,
  `hits` bigint(20) unsigned NOT NULL DEFAULT '1',
  `in_bytes` bigint(20) unsigned NOT NULL DEFAULT '0',
  `out_bytes` bigint(20) unsigned NOT NULL DEFAULT '0',
  `opt_pct` decimal(11,2) NOT NULL DEFAULT '0.00',
  `record_status` tinyint(3) unsigned NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  UNIQUE KEY `time_stamp` (`time_stamp`,`site_id`,`server_id`,`device_class_id`,`congestion_level_id`,`network_type_id`,`image_format_id`),
  KEY `fk_image_device_class_id3` (`device_class_id`),
  KEY `fk_image_congestion_level_id3` (`congestion_level_id`),
  KEY `fk_image_network_type_id3` (`network_type_id`),
  KEY `fk_image_site_id3` (`site_id`),
  KEY `fk_image_server_id3` (`server_id`),
  KEY `fk_image_format3` (`image_format_id`),
  KEY `image_time_record_status3` (`time_stamp`,`record_status`),
  CONSTRAINT `fk_image_congestion_level_id3` FOREIGN KEY (`congestion_level_id`) REFERENCES `congestion_level` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk_image_device_class_id3` FOREIGN KEY (`device_class_id`) REFERENCES `device_class` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk_image_format3` FOREIGN KEY (`image_format_id`) REFERENCES `image_format` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk_image_network_type_id3` FOREIGN KEY (`network_type_id`) REFERENCES `network_type` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk_image_server_id3` FOREIGN KEY (`server_id`) REFERENCES `server` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
  CONSTRAINT `fk_image_site_id3` FOREIGN KEY (`site_id`) REFERENCES `site` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2479561 DEFAULT CHARSET=latin1 |

有谁能解释一下原因吗?

EN

回答 2

Stack Overflow用户

发布于 2014-07-10 04:58:33

这似乎与索引选择性有关。您在tinyint列上有一个索引,与记录数量相比,该列的不同值很少。除非索引覆盖了一个查询(就像第一个查询一样-它是innodb表,并且主键列隐式地包含在辅助索引中),优化器(基于统计数据)决定全表扫描比索引范围扫描+查找更便宜。

票数 2
EN

Stack Overflow用户

发布于 2014-07-10 04:58:55

id是一个主键,因此是InnoDB表中每个索引的一部分。

当您运行第一个查询时,所需的所有数据(过滤和选定字段)都包含在索引本身中,因此只需扫描索引就足以运行查询。

从explain输出中的Using where; Using index可以看出:using index部分表示这是仅限索引的扫描。

在第二个查询中,server_id不是record_status上的索引的一部分。这意味着,如果MySQL选择了索引访问方法,则必须在嵌套循环中查找每个索引记录的相应表记录,以检索server_id的值。

这是一个相当昂贵的操作,而且您的大多数记录都有record_status = 1 (MySQL知道这一点,因为它保留索引键分布的直方图)。

因此,优化器选择仅执行表扫描,因为所有数据都在表中,而且大多数表记录无论如何都必须检索,但效率较低。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24663553

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档