我已经在mySQL 5.0.51a中解决了这个问题很长一段时间了:
当使用LEFT JOIN连接表并在WHERE子句中使用连接表的列时,mySQL无法在JOIN中使用连接表的主索引,甚至FORCE INDEX(PRIMARY)也失败。
然而我需要他们两个。
故障: (在我的特殊情况下,长达1000秒的执行时间)
SELECT *
FROM tbl_contract co
LEFT JOIN tbl_customer cu ON cu.customer_id = co.customer_id
WHERE cu.marketing_allowed = 1 AND co.marketing_allowed = 1
GROUP BY cu.id
ORDER BY cu.name ASC
工作,但没有解决我的问题:
SELECT *
FROM tbl_contract co
LEFT JOIN tbl_customer cu ON cu.customer_id = co.customer_id
GROUP BY co.id
表结构(转录,因为真实表更复杂)
tbl_contract:
id: INT(11) PRIMARY
customer_id: INT(11)
marketing_allowed: TINYINT(1)
tbl_customer:
customer_id: INT(11) PRIMARY
marketing_allowed: TINYINT(1)
mySQL EXPLAIN在加入时注意到PRIMARY为可能的键,但不使用它。
有一个解决方案:
SELECT (...)
HAVING cu.marketing_allowed = 1
解决问题 BUT 我们在其他上下文中使用查询,我们只能在整个语句中选择一列,但是HAVING需要在SELECT-Statement中选择marketing_allowed列。 / p>
我还注意到,在所需的表上运行ANALYZE TABLE会使我本地系统上的mySQL 5.5.8做正确的事情,但我不能总是确保在语句之前运行了ANALYZE。无论如何,这个解决方案在我们的高效服务器上的mySQL 5.0.51a下不起作用。 :(
mySQL中是否有一条我没注意到的特殊规则?如果列出现在WHERE子句中,为什么不使用LEFT JOIN索引?为什么我不能强迫他们?
提前,
勒
[编辑]
感谢一些回复,我可以使用INNER JOIN优化查询,但不幸的是,虽然看起来绝对正常,但mySQL在使用ORDER BY子句时仍然拒绝使用索引,我发现:
SELECT *
FROM tbl_contract co
INNER JOIN tbl_customer cu ON cu.customer_id = co.customer_id AND cu.marketing_allowed = 1
WHERE cu.marketing_allowed = 1
ORDER BY cu.name ASC
如果退出ORDER BY,mySQL将正确使用索引。 我删除了GROUP BY,因为它与示例无关。
[EDIT2]
强迫索引也无济于事。所以,问题是:为什么mySQL不使用索引进行连接,因为在加入WHERE子句并减少WHERE子句的结果集后执行ORDER BY?这通常不会影响加入......
答案 0 :(得分:1)
我不确定我明白你在问什么,但是
SELECT *
FROM tbl_contract co
LEFT JOIN tbl_customer cu ON cu.customer_id = co.customer_id
WHERE cu.marketing_allowed = 1 AND co.marketing_allowed = 1
不会进行外连接(因为cu.marketing_allowed = 1
)。
您可能打算使用:
SELECT *
FROM tbl_contract co
LEFT JOIN tbl_customer cu
ON cu.customer_id = co.customer_id
AND cu.marketing_allowed = 1
WHERE co.marketing_allowed = 1
答案 1 :(得分:1)
我遇到了同样的麻烦。在条件使用JOIN时,MySQL优化器不使用索引。我将我的SQL语句从JOIN更改为子查询:
SELECT
t1.field1,
t1.field2,
...
(SELECT
t2.field3
FROM table2 t2
WHERE t2.fieldX=t1.fieldX
) AS field3,
(SELECT
t2.field4
FROM table2 t2
WHERE t2.fieldX=t1.fieldX
) AS field4,
FROM table1 t1
WHERE t1.fieldZ='valueZ'
ORDER BY t1.sortedField
这个请求要复杂得多,但是当使用索引时,它的速度也会快得多。
您也可以使用STRAIGHT_JOIN
但上述查询的效果会更好。这是DB与table1中的100k行和table2中的20k的比较:
STRAIGHT_JOIN
JOIN
答案 2 :(得分:0)
您是否在JOIN子句中尝试了多个条件?
SELECT *
FROM tbl_contract co
LEFT JOIN tbl_customer cu ON cu.customer_id = co.customer_id AND cu.marketing_allowed = 1
WHERE co.marketing_allowed = 1