【问题标题】:MySQL subquery in the same table kills performance同一张表中的 MySQL 子查询会降低性能
【发布时间】:2017-01-14 04:23:10
【问题描述】:

基本上,我正在尝试根据用户兴趣创建一个“建议”页面。

在一个累积表中,我存储了每个用户看到的所有产品。我的想法是选择所有访问过我看到的产品的人的所有看到的产品。我一直在尝试提出一个查询,但我最好的主意是

  • a) 很少有查询
  • b) 子查询

问题是,如果我的表增长,我认为用很少的查询来做这件事是不可扩展的。使用子查询时,我的查询破坏了我的数据库,即使当我使用 EXPLAIN 时一切看起来都很好(没有临时表,没有磁盘命中)但是当我原始查询时,它需要一分钟多的时间才能执行......在一个 ~40k 的表中行。一个一个地运行查询在一秒钟内完成了我想要的,所以我真的很困惑。我在哪里做错了?

该表有以下列 id (PRIMARY)、user_id、product_id 和一堆不需要的字段

以下是我提出的 SQL 查询(它会杀死我的服务器)

SELECT product_id
FROM user_behavior
WHERE user_id
IN (

    SELECT user_id
    FROM user_behavior
    WHERE user_id <> 43456
    AND product_id
    IN (

        SELECT product_id
        FROM user_behavior
        WHERE user_id =43456
        GROUP BY product_id
    )
    AND offer_city_id
    IN ( 0, 2 )
)

正如我所说,运行解释返回以下内容

| id    | select_type           | table             | type              | possible_keys         | key       | key_len   | ref       | rows      | Extra                     |
|----   |--------------------   |---------------    |----------------   |-------------------    |---------  |---------  |-------    |-------    |-------------------------- |
| 1     | PRIMARY               | user_behavior     | index             | NULL                  | user_id   | 8         | NULL      | 25800     | Using where; using index  |
| 2     | DEPENDENT SUBQUERY    | user_behavior     | index_subquery    | user_id,user_id_2     | user_id   | 4         | func      | 3         | Using where               |
| 3     | DEPENDENT SUBQUERY    | user_behavior     | ref               | user_id,user_id_2     | user_id   | 4         | const     | 76        | Using where; using index  |

编辑:对不起,我无法想象表格:(

【问题讨论】:

    标签: mysql optimization subquery


    【解决方案1】:

    不要使用IN ( SELECT ... )

    我对查询试图做的事情很迷茫,但切换到JOINEXISTS 可能是解决方案的一部分。也许接近这个:

    SELECT  s.product_id
        FROM  user_behavior AS a
        JOIN  user_behavior AS b  ON b.user_id = a.user_id
        WHERE  EXISTS (
                  SELECT  *
                      FROM  user_behavior
                      WHERE  product_id = b.product_id
                        AND  user_id = 43456
                      )
          AND  b.offer_city_id IN ( 0, 2 )
          AND  b.user_id <> 43456 
    

    并包含一个“复合”INDEX(user_id, product_id)(以任意顺序)

    或者也许只需要这个??...

    SELECT DISTINCT product_id
        FROM  user_behavior AS b
        WHERE  EXISTS (
                  SELECT  *
                      FROM  user_behavior
                      WHERE  product_id = b.product_id
                        AND  user_id = 43456
                      )
          AND  offer_city_id IN ( 0, 2 )
          AND  user_id <> 43456 
    

    嗯,我希望你能从这些尝试中得到一些想法。

    【讨论】:

    • 第二个查询正是我所需要的。我不知道 EXISTS 究竟是如何工作的,但我将继续阅读 MySQL 文档并尝试掌握它。谢谢!
    • EXISTS 是一个“半连接”,它类似于JOIN,但在找到匹配项时停止。然后它只返回 True 或 False;不要被*误导。
    猜你喜欢
    • 2014-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    相关资源
    最近更新 更多