2012-02-06 62 views
1

當我隔離了這個查詢:使用MySQL「in」導致循環?

SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`) 
WHERE `Tag`.`id` = 137; 

我得到:

+------------+ 
| contact_id | 
+------------+ 
|  3519 | 
|  17080 | 
+------------+ 

但是,當我用「IN」一個大的查詢結合起來,我得到某種形式的遞歸循環的和我的數據庫開始進食提高處理能力直至超時。

SELECT `Contact`.* 
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`) 
WHERE `Tag`.`id` = 137); 

這只是繼續運行,直到我重置服務器。

但後來它的工作原理,當我手動列出的第一個查詢響應:

SELECT `Contact`.* 
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(3519, 17080); 

的區別是什麼?

+0

SQL不會卡在循環中,除非明確使用循環。如果運行時間過長,則可能意味着查詢非常昂貴。您的數據庫中有多少數據可以運行? – deceze 2012-02-06 02:12:05

+0

你有什麼指標在表中? – 2012-02-06 02:17:06

+0

此外,爲了提高性能,請考慮對子查詢使用JOIN,而不要使用IN(...)。例如,看看這個問題的接受答案:http://stackoverflow.com/questions/8713476/join-table-on-itself-performance/8713527 – Umbrella 2012-02-06 04:14:33

回答

1

目前MySQL的GA版本是真的在優化子查詢方面不好。有可能在Contacts的每一行中執行子查詢。如果你運行EXPLAIN your_query_here,你可以看到這個。你會發現子查詢已被標記爲DEPENDENT SUBQUERY

這不是一個好的解決方案,但類似的東西可能會起作用。

"SELECT `Contact`.* 
FROM `contacts` AS `Contact` 
WHERE `Contact`.`id` in 
(SELECT * FROM (SELECT `Tagged`.`contact_id` 
FROM contacts_tags AS Tagged LEFT JOIN tags AS Tag ON (`Tagged`.`tag_id` = `Tag`.`id`) 
WHERE `Tag`.`id` = 137) x);" 

這應該強制MySQL緩存子查詢。或者,如果您知道查詢將返回少量值,則只需執行兩個單獨的查詢即可。

0

如果一個着眼於子查詢

SELECT ct.contact_id 
FROM contacts_tags AS ct 
LEFT JOIN tags AS t ON ct.tag_id = t.id 

然後它不會限制contact_tags:刪除LEFT的限制(等值連接)。

改寫它看起來像:

SELECT DISTINCT c.* 
FROM contacts AS c 
JOIN tags AS t ON c.id = t.contact_id 
JOIN contacts_tags AS ct ON ct.tag_id = t.id 
WHERE 
    t.id = 137 

SELECT c.* 
FROM contacts AS c 
JOIN tags AS t ON c.id = t.contact_id 
WHERE 
    t.id = 137 
AND 
    EXISTS(SELECT * 
    FROM contacts_tags AS ct 
    WHERE ct.tag_id = 137) 

這僅僅是怪異。它看起來像缺少一些條件。