简体   繁体   English

MySQL:如何简化“IN”查询

[英]MySQL: How to simplify a “IN” query

I know that I have to avoid to use "IN" clause, but I don't know how to do in this case.我知道我必须避免使用“IN”子句,但我不知道在这种情况下该怎么做。 The scenario is this: from PHP I get a list of values and then I construct a query like this:场景是这样的:从 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

This makes my site very slow (because it is executed each time a user visits it).这使我的网站非常慢(因为每次用户访问它时都会执行它)。 How can make it faster?怎样才能让它更快?

I believe you can simplify the query to:我相信您可以将查询简化为:

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

Using NOT EXISTS instead of the LEFT JOIN may also buy you some additional performace.使用NOT EXISTS而不是LEFT JOIN也可以为您带来一些额外的性能。 Try each and compare.尝试每个并进行比较。

 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

Get rid of sub-selects .摆脱子选择 The IN() clause is perfectly ok. IN()子句完全没问题。

Following AJ's request for writing down the corrected query:在 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

The above code is not tested and may contain some serious mistakes (was written ad hoc) - if you find any, please give me feedback in the comments.上述代码未经测试,可能包含一些严重错误(临时编写) - 如果您发现任何错误,请在评论中给我反馈。

Plus

Do not forget to add proper indexes.不要忘记添加适当的索引。

I noticed that the IN is a sequential series of the values我注意到 IN 是一系列的值

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

You can just replace the IN here with您可以将此处的 IN 替换为

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

Much faster, because you only have to do 3 comparisons worst case.快得多,因为您只需要在最坏的情况下进行 3 次比较。

If you have random values如果你有随机值

Use a temp memory table.使用临时 memory 表。
With a hash primary key.使用 hash 主键。
And do an inner join on the primary hash key.并在主 hash 键上进行内部连接。

Time this and tell me how much faster it went:-)计时并告诉我它有多快:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM