【问题标题】:MySQL query too slow with GROUP BY使用 GROUP BY 的 MySQL 查询太慢
【发布时间】:2013-03-19 17:06:40
【问题描述】:

我有两张桌子:postscategoriesposts table 大约有 360,000 lines

我只想显示每个类别的第一篇文章,按日期排序并使用分页。

查询:

SELECT * FROM 
   (SELECT * FROM posts ORDER BY date_post DESC) as temp 
   GROUP BY id_category ORDER BY date_post DESC 
   LIMIT $offset, $limit"

该查询大约需要 1 分钟才能加载并显示我的网站。

我尝试将 MyISAM 更改为 InnoDB 并使用分区但未成功。

网站托管的服务器是专用服务器,我认为问题不在于它。

有人有什么建议吗?

【问题讨论】:

  • 如果没有太多的类别,也许每个类别都写一个查询比较好?
  • 您的查询中没有聚合函数,因此 GROUP BY 在这种情况下是多余的。也许您的意思是 DISTINCT?
  • 就目前而言,为什么不直接使用 SELECT * FROM 帖子作为临时文件,而不是放入第二个 SELECT 呢?
  • 我已经尝试过 DISTINCT,但我需要回显超过 1 列。使用 DISTINCT 我无法显示我想要显示的所有列
  • 您确定数据库是瓶颈吗?意思是,通过更简单的查询,页面是否按预期加载?

标签: php mysql


【解决方案1】:

您可以按如下方式简化查询:

   SELECT * 
   FROM posts
   GROUP BY id_category
   ORDER BY date_post DESC 
   LIMIT $offset, $limit

我不确定你想用子查询完成什么。也不确定是否需要 GROUP BY,但把它留在了那里。

【讨论】:

  • +1 - GROUP BY 将为每个 id_category 记录返回一条记录。这就是她正在寻找的东西,所以它是必需的。
  • 实际上每个类别的第一个帖子应该是ASC
  • 我已经尝试过这种方法,它有效,但太慢了.. 无论如何,谢谢! :D
【解决方案2】:

您的查询不正确,因为您使用的是non-aggregated columns in a GROUP BY query,并且这些列的值可能是不确定的(您不能保证您会得到第一个帖子)。

不知道它是否更快,但如果你确定没有多个帖子具有相同的时间戳,你可以使用这个:

SELECT posts.*
FROM
  posts INNER JOIN (
    SELECT
      id_category, MAX(date_post) mx_date
    FROM
      posts
    GROUP BY
      id_category
  ) mx ON posts.id_category=mx.id_category
          AND posts.date_post=mx.mx_date
ORDER BY
  posts.date_post DESC
LIMIT $offset, $limit

请看小提琴here

当然,请确保您在 id_categorydate_post 上都有索引。如果您想考虑一个事实,即多个帖子可以共享相同的时间戳,我们需要一个 id,我们需要再添加一个加入。

【讨论】:

  • 它有效,但仍然很慢.. 看,问题不是我收到的数据,而是处理时间。还是谢谢你:D
  • @AllissonFerreira 您的查询通常会起作用,但它没有记录在案,如果您更改平台或升级服务器,它可能会返回错误数据。在这里提高性能唯一可以做的就是使用索引。
【解决方案3】:

你需要重构查询:

SELECT posts.* FROM
(
    SELECT id_category,MAX(date_post) date_post
    FROM posts GROUP BY id_category
) postkeys LEFT JOIN posts USING (id_category,date_post);

这应该为您提供每件产品以及该产品的最新帖子。

警告

我故意将 LIMIT 子句移到子查询中,以生成所需的 id 范围。这工作非常非常快!!!

我已经为 YouTube 视频学习了这项技术:http://www.youtube.com/watch?v=ZVisY-fEoMw&feature=share&list=PL0194B59719B45A96

我将此应用于我在 StackOverflow 中回答的帖子问题:Fetching a Single Row from Join Table

试试看!!!

【讨论】:

  • 几乎做到了!加载时间约为 10 秒。但我注意到查询每天显示几篇文章。示例:我昨天注册了10个不同类别的产品,应该先显示这20个产品,但它只显示了3..昨天注册了20个不同类别的产品,只显示了6个。
  • 我打错字了,上面写着GROUP BY id _category。我将其更改为GROUP BY id_category。请再试一次...
  • 我看到当我尝试你的代码时,我在测试之前对其进行了更改:P
  • 我再次更改了查询。我将订单移到子查询之外。
  • 现在订单看起来完全是随机的,它显示了 2 月、3 月、1 月注册的产品。我尝试将 LIMIT 与 ORDER BY 移到子查询之外,并将 ORDER BY 移到内部和子查询之外的 LIMIT .. 这两次尝试的结果与您的第一个提示相同。
猜你喜欢
  • 1970-01-01
  • 2021-02-13
  • 1970-01-01
  • 2013-05-30
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多