2014-07-09 82 views
1

如果我選擇一列這是不是在我的表的外鍵,我覺得指數:索引中選擇一個外鍵

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 | 

人解釋爲什麼?

回答

2

它似乎與指數選擇性有關。您在tinyint列上有一個索引,與記錄數相比,它有很少的不同值。除非索引覆蓋查詢(如第一個 - 它是innodb表,並且主鍵列隱式包含在二級索引中),優化器(基於統計數據)決定全表掃描比索引範圍掃描+查找便宜。

2

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

當您運行第一個查詢時,您需要的所有數據(篩選和選定字段)都包含在索引本身中,因此只需掃描索引就足以運行查詢。

您可以在解釋輸出中通過Using where; Using index告知:using index部分表示它是僅索引掃描。

在您的第二個查詢中,server_id不是record_status上索引的一部分。這意味着MySQL如果選擇了索引訪問方法,就必須在嵌套循環中爲每個索引記錄查找相應的表記錄以檢索server_id的值。

這是一個相當昂貴的操作,並且大部分記錄都有record_status = 1(MySQL知道這是因爲它保留了索引鍵分佈的直方圖)。

因此,優化器選擇僅執行僅表掃描,因爲表中的所有數據都存在,並且大多數表記錄都必須以任何方式檢索,但效率較低。