【问题标题】:MySQL Query Slow with ORDER BY使用 ORDER BY 时 MySQL 查询缓慢
【发布时间】:2020-05-15 12:52:18
【问题描述】:

所以当我添加ORDER BY date_last_access DESC 时遇到问题,整个查询会减慢到 3 秒,没有它大约是 0.2 秒,为什么它运行这么慢,我该如何更改查询以更快地运行?

所有使用的表和字段也有索引。

用户:1+ 百万条记录 点赞数:5+ 百万条记录(超过 10 亿条生产量)

一旦投入生产,表格将增长得非常快。

查询

SELECT
    id,
    sid,
    first_name,
    date_birth,
    location,
    date_created,
    date_last_access,
    (3956 * 2 * ASIN(
        SQRT(
            POWER(
                SIN(
                    ({LAT} - latitude) * pi() / 180 / 2
                ),
                2
            ) + COS({LAT} * pi() / 180) * COS(latitude * pi() / 180) * POWER(
                SIN(
                    ({LON} - longitude) * pi() / 180 / 2
                ),
                2
            )
        )
    )) AS distance
FROM
    users
WHERE
    `id` != {UID} AND
    `gender` = {GEND} AND
    `date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
    `status` = 'active' AND
    (SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0
HAVING distance <= {DIST}
ORDER BY date_last_access DESC
LIMIT {ROWS}

解释

1   PRIMARY users   ref PRIMARY,Index_2,discovery,index_1   index_1 2   const   226184  Using index condition; Using where; Using filesort
2   DEPENDENT SUBQUERY  likes   eq_ref  PRIMARY,index_1,index_2 PRIMARY 16  const,hello.users.id    1   Using index

索引

喜欢 - user_id, judged_user - 正常 - BTREE

用户 - idgenderdate_birthstatusdate_last_access - 正常 - BTREE

当我通过id 而不是date_last_access 订购时,它似乎运行得更快,可能是因为 date_last_access 是datetime 格式吗?

【问题讨论】:

  • 你有date_last_access 的索引吗?
  • 所有使用的表和字段也有索引:请告诉我们您在users 表上有哪些索引。
  • @Nick - 我愿意
  • 建议编辑您的问题以包含更多信息。

标签: mysql sql database


【解决方案1】:

首先尝试运行您的查询的 EXPLAIN。这将向您显示哪些字段和操作会降低您的查询速度。然后尝试使用索引列进行连接,并使用更具体的值过滤您的结果集。

【讨论】:

  • 尝试使用左连接代替子查询过滤表“like”的空或零结果
【解决方案2】:

简化子查询可能是避免额外处理时间 (COUNT) 的更好方法:

(SELECT COUNT(*) FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID}) = 0

可以改成

(SELECT 1 FROM likes WHERE likes.judged_user = users.id AND likes.user_id = {UID} limit 1) IS NULL

避免子查询可能是提高查询性能的最佳方式。您可以检查哪些选项更适合您的情况(在这种情况下需要likes.user_id 的索引)

FROM
    users
LEFT JOIN (
SELECT distinct judged_user FROM likes WHERE likes.user_id = {UID}
) l ON l.judged_user=users.id
WHERE
    `id` != {UID} AND
    `gender` = {GEND} AND
    `date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
    `status` = 'active' AND
    l.judged_user is NULL

【讨论】:

  • 所以我把最后一个选项放进去,节省了一点时间,这很好,谢谢。仍然遇到date_last_access 仍然显着减慢它的问题。我已经快速处理了数十亿条记录,所以在我不得不再次担心之前还有很多时间,只是在订购时它会变慢。 ://
  • 不幸的是,id != {UID} 性能不佳(不使用索引)和 ORDER BY(将扫描所有行),因此您可以尝试在 'date_birth, status,gender 上创建索引' (按此顺序,从高基数到低基数),然后让引擎完成其余的工作(尝试删除 != 条件以查看差异)
【解决方案3】:

您应该将FROM 子句表述为:

WHERE `id` <> {UID} AND
      `gender` = {GEND} AND
      `date_birth` BETWEEN {DOB_MIN} AND {DOB_MAX} AND
      `status` = 'active' AND
       NOT EXISTS (SELECT 1 FROM likes l WHERE l.judged_user = users.id AND l.user_id = {UID}) 
HAVING distance <= {DIST}

对于这个查询,你可以尝试两个索引:

  • LIKES(judged_user, user_id)
    • USERS(Gender, status, date_birth, id)

【讨论】:

  • 该部分在超过 10 亿条记录中运行良好,问题是 ORDER BY 当我添加它时它会减慢它的速度。
猜你喜欢
  • 2021-04-22
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 2019-08-21
  • 1970-01-01
相关资源
最近更新 更多