我有两个名为个人资料和详细信息的表。详细信息表具有列城市的索引。这是我的疑问:
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中是否有任何限制,在这种情况下它不使用索引。
答案 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)