【问题标题】:query with dependent subqueries too slow带有依赖子查询的查询太慢
【发布时间】:2017-09-13 09:33:00
【问题描述】:
select  mt.from_user, mt.to_user, mt.group_id, g.name, g.created_by as adminuser,
        msg.*, 
    (
        SELECT  id
            from  messages
            where  t.thread_id = thread_id
              and  id NOT IN (
                SELECT  message_id  from  message_deleted
                    where  user_id=275  and  status='deleted' )
            order by  CreatedDate DESC
            limit  1
    ) as msgid, 
    (
        SELECT  CreatedDate
            from  messages
            where  t.thread_id = thread_id
              and  id NOT IN (
                SELECT  message_id  from  message_deleted
                    where  user_id=275  and  status='deleted'  )
            order by  CreatedDate DESC
            limit  1
    ) as msgDate
    from  user_thread as t
    left join  message_thread as mt  ON t.thread_id = mt.id
    left join  group_master as g  ON mt.group_id = g.id
    left join  group_member as gm  ON gm.group_id = g.id
    left join  messages as msg  ON t.thread_id = msg.thread_id
    where  (      gm.user_id=275
              or  msg.from_id=275
              or  msg.to_id=275
           )
      and  t.status = 'Active'
    group by  mt.id
    order by  msgDate DESC 

这大约需要 50 秒。

在上面的代码中,我尝试拆分上面的查询并注意下面的子查询需要太多时间来执行。我可以将子查询转换为联接吗?请帮我。我被卡住了。请注意,所有连接的表都是必需的。

    (
        SELECT  id
            from  messages
            where  t.thread_id = thread_id
              and  id NOT IN (
                SELECT  message_id  from  message_deleted
                    where  user_id=275  and  status='deleted' )
            order by  CreatedDate DESC
            limit  1
    ) as msgid, 
    (
        SELECT  CreatedDate
            from  messages
            where  t.thread_id = thread_id
              and  id NOT IN (
                SELECT  message_id  from  message_deleted
                    where  user_id=275  and  status='deleted'  )
            order by  CreatedDate DESC
            limit  1
    ) as msgDate

【问题讨论】:

  • 如果您没有找到解决方案,请考虑调整内存设置或硬件升级。 SSD 或 ramdisk 就像是加快速度的魅力。
  • 子查询通常不会加快速度:-)。除此之外:分组行与那里无关,我实际上应该触发错误消息。因为您的查询中没有像 count() 或 sum() 这样的聚合函数
  • 你试图通过这些子查询检索什么?
  • 或许可以试试把这个放到Code Review
  • 欢迎来到 Stack Overflow。请每个问题只问一个问题。您的 codeigniter 问题是您的第二个问题。请阅读这个。 meta.stackoverflow.com/a/271056 并特别注意第二个查询性能。请edit您的问题添加必要的详细信息。

标签: php mysql codeigniter query-performance


【解决方案1】:

首先,您滥用了对GROUP BY 的臭名昭著的 MySQL 扩展。这可能会导致您的结果不可预测。读这个。 https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

其次,您有几个嵌套的依赖子查询。其中第一个是这个。

(select id 
   from messages
  where t.thread_id = thread_id
    and id NOT IN (select message_id
                     from message_deleted
                    where user_id=275
                      and status='deleted') 
  order by CreatedDate DESC limit 1) as msgid

众所周知,这种嵌套的依赖子查询性能很差。当它们包含LIMIT 子句时,它们甚至更糟。您解决此问题的方法是将其重构为一个独立的查询,然后加入它。

这可以代替查询来查找线程上最近未删除的消息。

          SELECT MAX(m.id) id, m.thread_id
            FROM messages m
            LEFT JOIN message_deleted d 
                        ON m.id = d.id
                       AND d.user_id = 275
                       AND d.status = 'deleted'
           WHERE d.id IS NULL
           GROUP BY m.thread_id

这使用LEFT JOIN .... IS NULL 模式代替NOT IN。它更快。它使用MAX(id) 方法在表中查找最近的行来代替ORDER BY CreatedDate DESC LIMIT 1 方法,这也快得多。这很好,因为它保证每个 thread_id 的值生成 0 或 1 行。这意味着您可以在 LEFT JOIN ... ON ... thread_id 操作中使用它,而不是向结果集中添加任何行。

您可以通过运行它来测试这个子查询。然后你将它加入到查询的其余部分,就像它是一个表一样。

SELECT whatever,
       q.id, r.CreatedDate
  FROM whatever
  LEFT JOIN (
          SELECT MAX(m.id) id, m.thread_id
            FROM messages m
            LEFT JOIN message_deleted d 
                        ON m.id = d.id
                       AND d.user_id = 275
                       AND d.status = 'deleted'
           WHERE d.id IS NULL
           GROUP BY m.thread_id
       ) q ON q.id = t.id
  LEFT JOIN messages r ON r.id = q.id

此处的第二个LEFT JOIN 操作用于从消息表中检索最新未删除消息的CreatedDate 值。

【讨论】:

  • 尊敬的 StackOverflow 同事:我希望我知道关于这类问题的好教程。它出现了很多。有什么指点吗?
  • 我的 id 和 CreatedDate 为空
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
相关资源
最近更新 更多