2012-05-10 55 views
2

我一直百思不得其解解決此問題在MySQL的5.0.51a現在相當長的一段:在mysql LEFT不使用索引聯接WHERE子句

當使用LEFT JOIN加入一個表,並使用WHERE子句中連接表的列,mySQL無法使用JOIN中連接表的主索引,即使FORCE INDEX(PRIMARY)也失敗。

  • 如果未連接的表的列在WHERE子句中,則一切正常。
  • 如果刪除GROUP BY,則也使用該索引。

但我需要他們兩個。

故障: (的EXEC時間在我的特殊情況下可達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 

解決了我們使用的查詢在其他情況下,我們只能選擇在整個聲明中一列問題,但有需求的marketing_allowed列在SELECT語句中被選中。

我也注意到,在所需的表上運行ANALYZE TABLE將會使mySQL 5.5.8在我的本地系統上做正確的事情,但我不能始終確保ANALYZE已經在語句前運行。無論如何,這個解決方案在我們的生產服務器上不能在mySQL 5.0.51a下運行。 :(

有MySQL中的特殊規則,我沒注意到?爲什麼LEFT JOIN不使用索引,如果列顯示在WHERE子句中?爲什麼我不能強迫他們?提前

THX ,

[編輯]

由於一些答覆,我可以用一個訂單時使用INNER JOIN優化查詢,但遺憾的是,雖然看似精絕,MySQL的仍然拒絕使用索引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,因爲它在示例中沒有相關性。

[編輯2]

FORCING索引也沒有幫助。所以,問題是:爲什麼mySQL不使用索引進行連接,因爲在連接和減少WHERE子句的結果集之後執行ORDER BY?這通常不應該影響加入...

+1

你怎麼知道「mySQL無法使用主索引」?你檢查過'EXPLAIN'的輸出嗎?你能把它包括在你的問題中嗎? – eggyal

+0

請分享表格結構。 –

+0

嗨,是的,我大量使用了EXPLAIN,午餐休息後我會修改我的請求;) –

回答

0

我不知道我理解你的要求,但

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 
+0

正如另一篇文章中提到的那樣,我在整理沒有客戶關聯的合同時遇到了一個問題。如果cu.customer_id不爲NULL,將導致mySQL不使用索引 –

+1

@RenéHerzog:顯然你不想要一個外連接,所以你爲什麼要使用它? –

+0

好吧,我只知道這個,我已經在研究,什麼樣的加入會是最好的? –

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 
+0

嗨,是的,這是我的第一個想法。必須整理沒有加入客戶的線路,因爲他禁止獲得營銷信息。 - 這導致了WHERE ... AND cu。customer_id不是NULL,這也會產生INDEX未被使用的問題。 :( –

+0

我怕我沒有得到「理清那些沒有加入客戶的臺詞」如果你的意思是淘汰,我相信你會一直使用INNER JOIN代替LEFT JOIN的..請解釋一下更 –

+0

也許我可能是一個不同的JOIN類型可以解決我的問題,我會檢查並報告thx至此 –

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,但上述查詢的性能會更好。這是一個有表1中的10萬行和20K表2中的比較通過DB:使用上面的查詢

  • 0.10s

    • 0.00S使用STRAIGHT_JOIN
    • 0.30使用JOIN