MySQL:如何简化“IN”查询

时间:2011-06-02 18:56:19

标签: mysql optimization

我知道我必须避免使用“IN”子句,但在这种情况下我不知道该怎么办。场景是这样的:从PHP我得到一个值列表,然后我构建一个这样的查询:

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

这使我的网站非常慢(因为每次用户访问它时都会执行)。如何让它更快?

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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

上述代码未经过测试,可能包含一些严重错误(专案撰写) - 如果您发现任何错误,请在评论中给我反馈。

不要忘记添加适当的索引。

答案 2 :(得分:1)

我注意到IN是一系列值的连续序列

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

您可以使用

替换此处的IN
WHERE (r.id = 20) OR (r.id BETWEEN 2 AND 18)

快得多,因为你只需做3次比较最坏的情况。

如果您有随机值

使用临时记忆表 使用哈希主键。
并在主哈希键上进行内连接。

计算时间并告诉我它的速度有多快: - )