2011-06-02 29 views
2

我知道我必須避免使用「IN」子句,但在這種情況下我不知道該怎麼辦。該方案是這樣的:從PHP我得到值的列表,然後我建立這樣的查詢:MySQL:如何簡化「IN」查詢

SELECT id FROM 
    (SELECT * FROM `tips` r 
     LEFT JOIN (SELECT tip FROM `tips_showed` WHERE user='8') AS a ON r.id=a.tip 
     WHERE a.tip IS NULL) AS t 
WHERE t.id IN 
    ('3','4','5','2','6','7','8','9','10','18', 
    '11','12','13','14','15','16','17','20') LIMIT 1 

這使得我的網站很慢(因爲它每次執行一個用戶訪問它)。如何使它更快?

+0

爲什麼不把'IN'移到子選擇? – Halcyon 2011-06-02 19:00:31

回答

4

我相信你可以簡化查詢:

SELECT t.id 
    FROM `tips` t 
     LEFT JOIN `tips_showed` a 
      ON t.id = a.tip 
       AND a.user = '8' 
    WHERE a.tip IS NULL 
     AND t.id IN ('3','4','5','2','6','7','8','9','10','18', 
        '11','12','13','14','15','16','17','20') 
    LIMIT 1 

使用NOT EXISTS代替LEFT JOIN也可以給你買一些額外的服務表現。嘗試每個和比較。

SELECT t.id 
    FROM `tips` t 
    WHERE t.id IN ('3','4','5','2','6','7','8','9','10','18', 
        '11','12','13','14','15','16','17','20') 
     AND NOT EXISTS(SELECT NULL 
          FROM `tips_showed` a 
          WHERE a.tip = t.id 
           AND a.user = '8') 
    LIMIT 1 
+0

我測試過,第一個是最快的。謝謝 – Ivan 2011-06-02 20:25:23

1

擺脫子選IN()子句完全正確。

繼AJ的要求寫下來更正查詢:

SELECT `r`.`id` 
FROM `tips` AS `r` 
LEFT JOIN `tips_showed` AS `a` 
ON (`a`.`user`='8' AND `r`.`id`=`a`.`tip`) 
WHERE `r`.`id` IN ('3','4','5','2','6','7','8','9','10','18', 
    '11','12','13','14','15','16','17','20') 
AND `a`.`tip` IS NULL 
LIMIT 1 

上面的代碼沒有進行測試,並可能包含一些嚴重的錯誤(寫入臨時) - 如果你發現任何,請給我反饋評論。

不要忘了添加適當的索引。

+0

如果您重新編寫查詢以顯示OP如何改進,將會很有幫助。 – 2011-06-02 19:04:26

+0

@AJ我已經根據您的請求寫下了我的建議版本,但它可能包含許多錯誤,例如從錯誤的表中獲取列。 – Tadeck 2011-06-02 19:19:15

1

我注意到,IN是一系列連續的值

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 and an extra number 20. 

的你可以只用

WHERE (r.id = 20) OR (r.id BETWEEN 2 AND 18) 

快得多更換這裏,因爲你只需要做3比較最壞的情況。

如果你有隨機值

使用臨時存儲器表。
使用散列主鍵。
並對主散列鍵進行內連接。

時間這個,告訴我它快多了:-)

+0

謝謝,但值可以隨機:) – Ivan 2011-06-02 20:24:59