为什么以下查询无法使用story_keywords表中的索引story_id?
mysql> EXPLAIN SELECT `stories`.*
-> FROM (`stories`)
-> JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
-> WHERE `image_full_url` != ''
-> AND `order` != 0
-> AND `news_type` IN ('movie', 'movie_review')
-> AND `keyword` IN ('topnews', 'toptablet')
-> GROUP BY `stories`.`id`
-> ORDER BY `created` DESC, `order` DESC
-> LIMIT 5 ;
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | story_keywords | ALL | story_id | NULL | NULL | NULL | 42 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | stories | eq_ref | PRIMARY | PRIMARY | 767 | entertainment.story_keywords.story_id | 1 | Using where |
+----+-------------+----------------+--------+---------------+---------+---------+---------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
mysql> show create table stories;
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| stories | CREATE TABLE `stories` (
`id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`news_type` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created` datetime DEFAULT NULL,
`author` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`author_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_caption` text COLLATE utf8_unicode_ci,
`image_credit` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_full_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`body` text COLLATE utf8_unicode_ci,
`summary` text COLLATE utf8_unicode_ci,
`external_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`order` int(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+---------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> show create table story_keywords;
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| story_keywords | CREATE TABLE `story_keywords` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`story_id` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`keyword` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `story_id` (`story_id`)
) ENGINE=MyISAM AUTO_INCREMENT=85 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+----------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
答案 0 :(得分:1)
可能是因为MySQL认为从story_keywords表中获取所有行并加入它们而不是使用索引会更便宜。一开始听起来很奇怪,但是,你看,如果你必须在一个表上执行100次索引查找,而这个表只有大约100行 - 读取所有行的成本会更低。解释很简单:索引查找(对于BTREE索引)是O(ln N),而读取N行是O(N)。显然,O(N)< N * O(ln N)。
要证明这一点 - 尝试从故事中选择一行(并且一个是指一行,而不是对整个表进行排序并限制结果;),就像:
SELECT `stories`.*
FROM (`stories`)
JOIN `story_keywords` ON `story_keywords`.`story_id` = `stories`.`id`
WHERE `stories`.id = SOMETHING
此查询更有可能转向story_keywords上的索引。
希望这能回答你的问题:)
答案 1 :(得分:1)
安东走在正确的轨道上,但我相信问题还有更多。正如我对OP的评论所说,id列很可能是INT
类型。如解释所示,stories
上主键的长度为767.通常对于INT
类型,长度将为低个位数,但由于列为VARCHAR
,长度非常长。
回到主要问题,因为stories.news_type
,stories.order
或story_keywords.story_keywords
上没有索引,优化程序决定对story_keywords
进行全面扫描,因为它将产生最小的初始结果集。如果其中一个列上有索引,则可能首先使用该索引。如果添加查询可以使用的索引,则无需执行全表扫描。