2011-12-21 205 views
3

SELECT中使用SELECT以減少查詢次數是很常見的;但正如我檢查這導致查詢緩慢(這顯然是有害的MySQL性能)。我有一個簡單的查詢,如在mysql查詢的SELECT中使用SELECT

SELECT something 
FROM posts 
WHERE id IN (
    SELECT tag_map.id 
    FROM tag_map 
    INNER JOIN tags 
    ON tags.tag_id=tag_map.tag_id 
    WHERE tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6') 
) 

這導致慢的查詢「查詢時間3-4s;鎖定約0.000090s時間;具有約200行檢查」。

如果我拆分SELECT查詢,它們中的每一個都會很快;但是這會增加高併發性不佳的查詢數量。

這是通常的情況,還是我的代碼有問題?

+2

''SELECT'內SELECT'?這就像那部電影... Inselection。 – 2011-12-21 05:53:27

回答

12

在MySQL中,做一個子查詢一樣,這是一個「相關查詢」。這意味着外部SELECT的結果取決於內部SELECT的結果。結果是你的內部查詢每行執行一次,這很慢。

您應該重構此查詢;無論你加入兩次還是使用兩次查詢都是無關緊要的。加入兩次會給你:

SELECT something 
FROM posts 
INNER JOIN tag_map ON tag_map.id = posts.id 
INNER JOIN tags ON tags.tag_id = tag_map.tag_id 
WHERE tags.tag IN ('tag1', ...) 

欲瞭解更多信息,請參閱MySQL手冊上converting subqueries to JOINs

提示:EXPLAIN SELECT將向您展示優化程序計劃如何處理您的查詢。如果你看到DEPENDENT SUBQUERY你應該重構,這是巨大的緩慢。

+1

中的子句查詢 – jclozano 2011-12-21 06:00:19

2

您可以通過使用改進如下:

SELECT something 
FROM posts 
INNER JOIN tag_map ON tag_map.id = posts.id 
INNER JOIN tags 
ON tags.tag_id=tag_map.tag_id 
WHERE <tablename>.tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6') 

只要確保你只選擇你所需要的,並且不使用*;還規定在該表必須在標籤欄,所以你可以替換<的tablename >

+0

這就是我們所說的** JOIN **。 – 2011-12-21 05:55:34

+0

是的,內部連接兩次,至少我認爲它快於子句 – jclozano 2011-12-21 05:57:16

1

聯合對結果進行過濾。第一次加入會保持第一個ON條件的結果,然後第二個條件在第二個ON條件下給出最終結果。

SELECT something 
FROM posts 
INNER JOIN tag_map ON tag_map.id = posts.id 
INNER JOIN tags ON tags.tag_id = tag_map.tag_id AND tags.tag IN ('tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6'); 

你可以看到堆棧溢出這些討論:

question1 question2

加入有助於降低時間複雜度和提高了服務器的穩定性。

轉換子查詢信息聯接:

link1 link2 link3