如果我在表格中选择一个不是外键的列,我会找到索引:
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)
另一方面,如果选择一个外键列,则找不到索引:
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)
以下是表格的定义:
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 |
任何人都可以解释原因吗?
答案 0 :(得分:2)
它似乎与索引选择性有关。您在tinyint列上有一个索引,与记录数相比,它具有非常少的不同值。除非索引覆盖了查询(如第一个 - 它的innodb表,并且主键列隐式包含在二级索引中),优化器(基于统计信息)决定全表扫描比索引范围扫描更便宜+抬头。
答案 1 :(得分:2)
您id
是主键,因此,它是InnoDB
表中每个索引的一部分。
当您运行第一个查询时,您需要的所有数据(过滤和选定字段)都包含在索引本身中,因此只需扫描索引即可运行查询。
您可以在解释输出中通过Using where; Using index
告诉:using index
部分表示它是仅索引扫描。
在您的第二个查询中,server_id
不是record_status
上索引的一部分。这意味着,如果MySQL选择了索引访问方法,则必须在嵌套循环中查找每个索引记录的相应表记录,以检索server_id
的值。
这是一项非常昂贵的操作,并且大多数记录都有record_status = 1
(MySQL知道这一点,因为它保留了索引键分布的直方图)。
因此优化器选择仅进行表格式扫描,因为表中的所有数据都存在,并且大多数表记录都必须被检索,但效率较低。