【问题标题】:EXISTS query optimization on mysql queryEXISTS 对 mysql 查询的查询优化
【发布时间】:2017-11-21 08:57:29
【问题描述】:

我在使用 MySQL 时遇到了大数据问题。

我有:

  • 一个有 59033 行的 users 表,并且
  • 一个有 8753 行的 user_notes 表。

但是当我搜索哪些用户在某些日期有用户注释时。

我的查询是这样的:

SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user 
LEFT JOIN authorization on authorization.id = u.authorization 
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation 
WHERE 
    EXISTS(
    select * from user_notes 
    where user_notes.note_user_id = u.id AND user_notes.create_date 
    BETWEEN "2017-10-20" AND "2017-10-22"
    )
ORDER BY u.lp_modify_date DESC, u.id DESC

【问题讨论】:

  • 你有什么问题...?
  • 重写为join,以获得更好的性能。
  • 从 user_notes 而不是用户驱动。
  • 避免存在而更喜欢Left Join,为什么要加入同一张表users?
  • 解释计划在哪里? (& 需要这些表上所有现有索引的详细信息。

标签: php mysql sql optimization exists


【解决方案1】:

转身——先找到id;稍后处理连接。

SELECT  u.*, 
        ( SELECT  rep.name
            FROM  users AS rep
            WHERE  rep.id = u.add_user ) AS rep_name 
    FROM  (
        SELECT  DISTINCT note_user_id
            FROM  user_notes
            WHERE  create_date >= "2017-10-20"
              AND  create_date  < "2017-10-20" + INTERVAL 3 DAY 
          ) AS un
    JOIN  users AS u  ON u.id = un.note_user_id
    ORDER BY  lp_modify_date DESC, id DESC

注意事项

  • 不需要GROUP BY
  • 2 个表似乎未使用;我删除了它们;
  • 我更改了日期范围;
  • 用户备注需要INDEX(create_date, note_user_id);
  • 注意我是如何将LEFT JOIN 变成SELECT 列表中的子查询的。

如果可以有多个rep_names,那么原始查询是“错误的”,因为GROUP BY 将选择一个随机名称。我的答案可以通过将rep.name 更改为以下之一来“修复”:

MAX(rep.name) -- deliver only one; arbitrarily the max

GROUP_CONCAT(rep.name) -- deliver a commalist of names

【讨论】:

  • ^1 用于反转。但是:每个用户是否有可能拥有多个“rep.name”?它需要是左连接吗?谁知道呢。
  • @Used_By_Already - 好收获。但是,我会抱怨GROUP BY 提供一个随机的“rep_name”。我稍微改变了我的答案。
【解决方案2】:

重写查询以使用 JOIN 而不是 EXISTS 检查 where 应该会加快速度。如果您然后按 user.id 对结果进行分组,它应该会给您相同的结果:

SELECT u.*, rep.name as rep_name FROM users as u
LEFT JOIN users as rep on rep.id = u.add_user 
LEFT JOIN authorization on authorization.id = u.authorization 
LEFT JOIN user_situation_list on user_situation_list.user_situation_id = u.user_situation 
JOIN user_notes AS un 
  ON un.note_user_id
  AND un.create_date BETWEEN "2017-10-20" AND "2017-10-22"
GROUP BY u.id
ORDER BY u.lp_modify_date DESC, u.id DESC

【讨论】:

    猜你喜欢
    • 2018-04-22
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    • 2011-01-22
    • 2011-07-07
    • 2018-12-21
    • 2010-12-15
    相关资源
    最近更新 更多