2011-05-13 74 views
4

我已經在MySQL 5.0,5.1,5.5上測試了以下看似簡單的查詢,發現它非常慢。MySQL子查詢真的很慢...解決方法?

select * from entry where session_id in 
    (select session_id from entry where created_at > [some timestamp]) 

多個條目可以具有相同的會話ID,但具有不同的created_at時間戳。 該查詢旨在獲取所有條目的來自同一個session_id,其created_at大於指定時間戳的至少一個條目。

我已經看到其他人談到類似查詢的MySQL子查詢性能問題,並且MySQL認爲子查詢是一個依賴查詢,並且它正在對外部查詢執行全表掃描。建議的解決方法是這樣的:

select * from entry where session_id in 
    (select session_id from 
     (select session_id from entry where created_at > [some timestamp]) 
    as temp) 

但是,這種黑客不適合我,並使其更慢。

有關如何重寫此查詢的任何想法?

回答

5

根據您的數據分發,使用此

SELECT e.* 
FROM (
     SELECT session_id, MAX(created_at) 
     FROM entry 
     GROUP BY 
       session_id 
     HAVING MAX(created_at) > $mytimestamp 
     ) ed 
JOIN entry e 
ON  e.session_id = ed.session_id 

(創建(session_id, created_at)索引),或這樣的:

SELECT DISTINCT e.* 
FROM entry ed 
JOIN entry e 
ON  e.session_id = ed.session_id 
WHERE ed.created_at > $mytimestamp 

(創建created_at和兩個單獨的索引session_id

+0

你達人。謝謝! 我從第二個查詢開始,但忽略了不同。我不知道你可以使用通配符將不同的結果應用於整個結果集。真棒。 – n00b 2011-05-13 22:05:28

1

如何:

SELECT DISTINCT e2.* 
    FROM entry e1 
     INNER JOIN entry e2 
      ON e1.session_id = e2.session_id 
    WHERE e1.created_at > [some timestamp] 

如果您還沒有他們,就created_atsession_id指標很可能是有幫助。

+0

你還需要'group by e2.id',否則你會得到重複的。 – 2011-05-13 22:02:07

+0

謝謝。實際上,這是我最初嘗試的。這是給我重複。對我來說沒有發生過使用分組。或者你可以使用不同的e2。*。 – n00b 2011-05-13 22:05:07

+0

新增更正。 – 2011-05-13 23:02:38

3

我也有一個雙子查詢技巧的問題, btw我剛剛發現,使用這個工作對我來說(根據您的查詢):

select * from entry where session_id in 
    (select (select session_id from entry where created_at > [some timestamp])) 

在我的情況下,原有的查詢可以使用一個連接或「正常」雙子查詢招小時,與修改後的雙子查詢用了0秒工作: )

+1

這是非常有用的,因爲很容易申請!然而奇怪的是MySQL的這種行爲...... – Pisu 2011-10-03 16:32:55

+1

只有在內部查詢返回單個結果的情況下,這才起作用。否則,你會得到錯誤「子查詢返回多於一行」 – ecdeveloper 2015-10-26 23:19:43