【问题标题】:MySQL Subquery, Join and Rank Query - Why very slow?MySQL 子查询、连接和排名查询 - 为什么很慢?
【发布时间】:2020-08-07 15:00:07
【问题描述】:

我的查询需要永远加载,members 中只有 800 多行,members_points 中只有 5,100 多行。

有没有我忽略的更有效的方法,或者使用 MySQL 5.5.33 编写此查询的另一种方法?

*更新:5.5 是我的本地主机,5.7 是实时服务器。没有看到任何明显的差异。

这是我目前所拥有的 - 感谢您的反馈

  $result = $conn->query("
  SELECT subquery.*, 
         @rank := @rank + 1 `rank`
  FROM (SELECT m.id, 
               m.Name,
               m.Column_1,
               m.Column_2,
               m.Column_3,
               SUM(m.id = mp.id_from) total_sent,
               SUM(m.id = mp.id_to) total_received,
               SUM(m.id = mp.id_from) - SUM(m.id = mp.id_to) `points`
        FROM members m
        INNER JOIN members_points mp
        WHERE Account_Active LIKE 'TRUE'
        GROUP BY m.id, 
                 m.Name) subquery, (SELECT @rank := 0) variable
  ORDER BY `points` DESC;
  ");

【问题讨论】:

  • 你知道 mysql 5.5 已经很老了而且被弃用了吗?
  • 您是否暗示问题不在于代码,而在于服务器设置?
  • 一如既往的优化查询需要一个EXPLAIN和Table的定义,但是mysql 5.5太旧了,所以试试用5.7看看有没有更快的。那是一个小型数据库,因此迁移应该像使用索引查询一样快速运行
  • Account_Active 在哪个表中?它在优化方面产生了的差异,我无法从您提供的内容中看出。它是VARCHAR 吗?该测试不检查真/假。请限定列提供SHOW CREATE TABLE
  • 活跃帐户在成员表中。它是 TINYTEXT。

标签: mysql performance subquery inner-join


【解决方案1】:
SELECT subquery.*, 
         @rank := @rank + 1 `rank`
  FROM (SELECT m.id, 
               m.Name,
               m.Column_1,
               m.Column_2,
               m.Column_3,
               SUM(m.id = mp.id_from) total_sent,
               SUM(m.id = mp.id_to) total_received,
               SUM(m.id = mp.id_from) - SUM(m.id = mp.id_to) `points`
        FROM members m
        INNER JOIN members_points mp
        WHERE Account_Active LIKE 'TRUE'
        GROUP BY m.id, 
                 m.Name) subquery, (SELECT @rank := 0) variable
  ORDER BY `points` DESC;
  ");

在做任何JOINs之前从计数开始。

SELECT id_from, COUNT(*) AS from_ct FROM members_points GROUP BY 1
SELECT id_to,   COUNT(*) AS   to_ct FROM members_points GROUP BY 1

然后将它们用作子查询并向外工作。

如果您希望或不希望包含与 不活跃 成员聊天的 活跃 成员,则可能会出现问题。表格有多少行?

现在看看这是否适合subquery

SELECT m.id, 
           m.Name,
           m.Column_1,
           m.Column_2,
           m.Column_3,
           froms.from_ct total_sent,
           tos.to_ct     total_received,
           froms.from_ct - tos.to_ct `points`
    FROM members m
    JOIN ( SELECT id_from, COUNT(*) AS from_ct FROM members_points GROUP BY 1
         ) AS froms  ON froms.id_from = m.id
    JOIN ( SELECT id_to,   COUNT(*) AS   to_ct FROM members_points GROUP BY 1
         ) AS tos    ON tos.id_to = m.id
    JOIN members_points mp
    WHERE m.Account_Active = 'TRUE'
    GROUP BY m.id, 
             m.Name

【讨论】:

  • 嗨瑞克。 MySQL 语法是 def。不是我的强项,虽然我理解这个概念,但恐怕我不太理解它来实现你所说的。只有活跃成员可以兑换积分,不活跃成员被隐藏。 members 表中只有 800+,member_points 中只有 5100+...考虑是否更好的方法是在 members 表中添加更多 3 列来总结事务(从 | 到 | 从到)并且每个事务写入members_points,然后更新成员总数? ...我只是觉得这不是最有效的路线?
  • @Andrew - 效率低下(我认为)主要是因为在计算SUMs 之前需要过滤“活动”。如果删除WHERE 子句,你会得到相同的答案吗?
  • 除了将非活动成员包括在查询中之外,它并没有明显的区别,查询仍然需要一分半钟才能运行...还尝试将结果限制为 10,但是也没有区别,因为计算需要首先运行以找出排名最高的 10 个
  • @Andrew - 我更进一步。
  • 正是我所希望的。将加载时间缩短了近 1 - 1 1/2 分钟....感谢 Rick 分享您的知识并帮助我更好地理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
相关资源
最近更新 更多