为什么Left outer Join没有正确使用索引

时间:2016-01-28 18:27:32

标签: mysql indexing left-join

我有两个名为个人资料和详细信息的表。详细信息表具有列城市的索引。这是我的疑问:

select * 
from profiles p 
left outer join details d 
use index(details_city) 
 on (p.id = d.pid) 
where (d.city = ‘york’ or p.city = 'york') 
order by p.id

当我对它进行解释时,我可以看到来自city列的详细信息表中的索引甚至没有被使用。

在MySQL中是否有任何限制,在这种情况下它不使用索引。

2 个答案:

答案 0 :(得分:2)

OR破坏了所有优化尝试。这应该更快,特别是如果表很大:

SELECT  p.*, d.*
    FROM  (
              -- Get what you can from `profiles`:
              ( SELECT  id
                    FROM  profiles
                    WHERE  city = 'york' 
              )
            UNION  DISTINCT 
              -- Get what you can by starting from `details`:
              ( SELECT  p.id
                    FROM  profiles p
                    JOIN  details d ON (p.id = d.pid)
                    WHERE  d.city = 'york' ) 
          ) AS u
    JOIN  profiles p ON p.id = u.id
    LEFT JOIN  details d ON d.pid = p.id
    ORDER BY  p.id

每个内部SELECT将使用不同的索引,因此可以进行优化。您将需要这些索引:

d:  INDEX(city, pid), INDEX(pid)
p:  PRIMARY KEY(id), INDEX(city, id)

您不应该需要任何形式的USE INDEX

(不要使用有趣的撇号:‘york’。)

OUTER是可选的,没有任何影响。)

(如果您需要city LIKE '%york%', consider FULLTEXT`。)

为什么,祈祷告诉你,两张桌子都有city吗?!?修复可能导致真正的解决方案。

答案 1 :(得分:1)

我怀疑你会看到内部联接的相同行为。在这个语句中,WHERE子句中的谓词否定了"外部性" LEFT JOIN。我不认为它与LEFT JOIN有任何关系。

使用WHERE子句中的谓词... city LIKE '%...',MySQL无法使用索引范围扫描操作。它必须为表格中的每一行(或者没有被过滤掉的每一行)评估city的值。

另外,您从details表中返回每个列,并且MySQL无法仅使用索引来满足该列,它会转到必须访问基础表中的页面以获取这些列的值。

MySQL正在判断一个不同的访问计划,其成本低于使用具有领先城市列的索引。在连接谓词 = d.pid 中进行了相等比较。 MySQL可以使用带有前导列的索引来满足该目标。

最有可能对此查询有益的索引是复合索引:

 ... ON details (pid, city)