MySQL:如何简化“IN”查询

问题描述:

我知道我必须避免使用“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

我相信你可以简化查询:

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

摆脱子选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

我注意到,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