我有一个音乐数据库,其中包含发布和发布标题的表格。此“releases_view”获取标题/ title_id以及曲目的替代标题/替代title_id。这是视图的代码:
SELECT
t1.`title` AS title,
t1.`id` AS title_id,
t2.`title` AS title_alt,
t2.`id` AS title_alt_id
FROM
releases
LEFT JOIN titles t1 ON t1.`id`=`releases`.`title_id`
LEFT JOIN titles t2 ON t2.`id`=`releases`.`title_alt_id`
联接表格中的title_id
和title_alt_id
字段均为int(11)
,title
和title_alt
为varchars。
问题
此查询将花费不到1毫秒:
SELECT * FROM `releases_view` WHERE title_id=12345
此查询也将花费不到1毫秒:
SELECT * FROM `releases_view` WHERE title_id=12345 OR title_alt_id!=54321
BUT:此查询将花费0.2秒。 慢了200倍!
SELECT * FROM `releases_view` WHERE title_id=20956 OR title_alt_id=38849
我很快就在WHERE子句中使用“=”进行了两次比较,事情确实变得很慢(尽管所有查询只有几个结果)。
你能帮我理解发生了什么吗?
修改
'EXPPL'显示了title_alt_id的USING WHERE,但我不明白为什么。我怎么能避免这个?
**编辑** 这是EXPLAIN DUMP。
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE releases NULL ALL NULL NULL NULL NULL 76802 Using temporary; Using filesort
1 SIMPLE t1 NULL eq_ref PRIMARY PRIMARY 4 db.releases.title_id 1
1 SIMPLE t2 NULL eq_ref PRIMARY PRIMARY 4 db.releases.title_alt_id 1 Using where
答案 0 :(得分:0)
“非常慢”是因为优化程序与OR
无法正常工作。
计划A(优化程序):扫描整个表格,评估整个OR
。
计划B:“索引合并联盟”可用于title_id = 20956 OR title_alt_id = 38849
,如果您在title_id
和title_alt_id
中有单独的索引:使用每个索引获取两个PRIMARY KEYs
列表和“合并”列表,然后到达表格以获取*
。多个步骤,不便宜。所以很少使用B计划。
title_id = 12345 OR title_alt_id != 54321
是一个谜,因为它应该返回大部分表。请提供EXPLAIN SELECT...
。
LEFT JOIN
(与JOIN
相对)需要假设“右”表中可能缺少该行。