EXPLAIN SELECT
*
FROM
content_link link
STRAIGHT_JOIN
content
ON
link.content_id = content.id
WHERE
link.content_id = 1
LIMIT 10;
+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+
| 1 | SIMPLE | link | ref | content_id | content_id | 4 | const | 1 | |
| 1 | SIMPLE | content | const | PRIMARY | PRIMARY | 4 | const | 1 | |
+----+-------------+---------+-------+---------------+------------+---------+-------+------+-------+
但是,当我删除WHERE时,查询将停止使用该键(即使我明确强制它)
EXPLAIN SELECT
*
FROM
content_link link FORCE KEY (content_id)
STRAIGHT_JOIN
content
ON
link.content_id = content.id
LIMIT 10;
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+
| 1 | SIMPLE | link | index | content_id | PRIMARY | 7 | NULL | 4555299 | Using index |
| 1 | SIMPLE | content | eq_ref | PRIMARY | PRIMARY | 4 | ft_dir.link.content_id | 1 | |
+----+-------------+---------+--------+---------------+---------+---------+------------------------+---------+-------------+
对此有什么解决方法吗?
我意识到我在第二个例子中选择了整个表,但是为什么mysql突然决定它会忽略我的FORCE并且不使用密钥?没有密钥,查询需要10分钟......呃。
答案 0 :(得分:4)
索引有助于在表格内快速搜索,但如果选择整个表格,它只会减慢速度。所以MySQL忽略索引是正确的。
在您的情况下,索引可能具有MySQL不知道的隐藏副作用。例如,如果内部联接仅保留几行,则索引会加快速度。但是,如果没有明确的提示,MySQL就无法知道。
有一个例外:当您选择的每个列都在索引中时,如果您选择每一行,索引仍然有用。例如,如果您在LastName上有索引,则以下查询仍然可以从索引中受益:
select LastName from orders
但是这个不会:
select * from Orders
答案 1 :(得分:4)
FORCE有点用词不当。以下是MySQL文档所说的内容(强调我的):
您还可以使用FORCE INDEX,其作用类似于USE INDEX(index_list),但另外还假设表扫描非常昂贵。换句话说,只有在无法使用某个给定索引在表中查找行时才使用表扫描。
由于您实际上并没有“找到”任何行(您正在全部选择它们),因此表格扫描始终将是最快的,并且优化程序足够智能以便尽快知道你告诉他们的是什么。
ETA:
尝试在主键上添加一次ORDER BY,我敢打赌它会使用索引。
答案 2 :(得分:0)
您的content_id
似乎接受NULL
值。
MySQL
优化器认为不能保证您的查询仅使用索引返回所有值(尽管实际上有保证,因为您使用了JOIN
中的列)
这就是它恢复全表扫描的原因。
添加NOT NULL
条件:
SELECT *
FROM content_link link FORCE KEY (content_id)
STRAIGHT_JOIN
content
ON content.id = link.content_id
WHERE link.content_id IS NOT NULL
LIMIT 10;
或将您的专栏标记为NOT NULL
:
ALTER TABLE content_link MODIFY content_id NOT NULL
<强>更新强>
MySQL
已对此进行了验证bug 45314。