【问题标题】:mysql pagination left join vs. union LIMITmysql分页左连接与联合限制
【发布时间】:2012-12-03 21:34:10
【问题描述】:

我有一个存储帖子的表“宝石”(例如博客)。对帖子的回复也存储在同一个表中,其中一个字段存储父帖子的键。每个帖子都可以附加文件。

我需要获取包含相关回复和附加文件的帖子列表。 因此,'gems' 有多个 LEFT JOINS 到它 - 一个到它自己,一个到带有文件名的 'gemdetail'。此查询有效:

SELECT g.gemid as gemidx, g.title, gemdetail.filename, r.gemid as rgemid, r.title, r.filename
FROM (SELECT * FROM gems WHERE gems.grade = '7' LIMIT 0, 10) g 
LEFT JOIN (SELECT x.title, x.gemid, x.replygemid, y.filename from gems x 
    LEFT JOIN gemdetail y ON x.gemid = y.gemid ) r ON g.gemid = r.replygemid 
LEFT JOIN gemdetail ON g.gemid = gemdetail.gemid 

但是,如果每个帖子有 20 个回复和 10 个文件,则每个帖子返回的记录数为 200。 LIMIT 子句有效,但这仍然是很多记录。再加上处理记录集很麻烦。

我重写了查询以使用 UNION,每个帖子将仅返回 40 条记录(而不是 200 条)。 UNION 有 4 个部分 - 1) 返回前 10 条记录 (LIMIT) 2) 获取帖子的文件名 3) 获取回复 4) 获取回复的文件名

下面的 UNION 查询有效,除了我不能限制 UNION 第一部分以外的任何返回记录的数量。我可以将 LIMIT 语句放入 UNION 的每个部分,但这是不正确的(我想将文件和回复限制在 LIMITed 10 个帖子的集合中)。当我尝试对任何 UNIONS 使用 WHERE gemid IN (SELECT gemid from gems....) 子句时,我得到了 mySQL 子查询限制错误。

SELECT g.gemid as gemidx, g.title, NULL as filename, NULL as rgemid, 'ag' as flag 
FROM (SELECT * FROM gems WHERE ISNULL(gems.replygemid) AND gems.grade = '7' LIMIT 0, 10) g
LEFT JOIN (SELECT * FROM gems) r ON g.gemid = r.replygemid  

UNION SELECT g.gemid as gemidx, g.title, gemdetail.filename as filename, NULL as rgemid, 'bf' as flag 
FROM (SELECT * FROM gems WHERE ISNULL(gems.replygemid) AND gems.grade = '7') g 
INNER JOIN gemdetail ON g.gemid = gemdetail.gemid

UNION SELECT g.replygemid as gemidx, g.title, NULL as filename, g.gemid as rgemid, 'cr' as flag 
FROM (SELECT * FROM gems WHERE NOT ISNULL(gems.replygemid) AND gems.grade = '7') g 

UNION SELECT g.replygemid as gemidx, g.title, gemdetail.filename as filename, g.gemid as rgemid, 'df' as flag 
FROM (SELECT * FROM gems WHERE NOT ISNULL(gems.replygemid) AND gems.grade = '7') g 
INNER JOIN gemdetail ON g.gemid = gemdetail.gemid 

ORDER BY gemidx desc, rgemid, flag

请帮忙。有没有办法有效地选择(为了分页)仅 10 个帖子及其所有相关的回复和文件?感谢您花时间阅读本文。我在这上面花了 2 天时间,并且处于我的极限(糟糕的双关语......)。

【问题讨论】:

  • 您可能可以为每个响应动态添加一个序列号,从 0 开始为每个帖子的第一个响应,然后只需选择序列号小于 X 的那些。
  • 有趣的想法...假设您指的是 UNION,我仍然看不到我是如何仅从 UNION 第一部分限制的帖子中选择回复的?

标签: mysql pagination left-join limit union


【解决方案1】:

有点玩,但这段代码有点讨厌,所以你可能不想使用它。不过,这暂时忽略了文件。请注意,我在我的一张桌子上得到了类似的东西,然后从中得到了这个,但我没有直接测试过,所以可能有错别字。

SELECT gems.gemid as gemidx, gems.title, r.gemid as rgemid, r.title, r.filename
FROM gems
INNER JOIN (SELECT gems.*, @runningtotal:=@runningtotal+1 AS CurrentTotal
FROM (SELECT @runningtotal := 0)Deriv1, gems 
ORDER BY replygemid) r
INNER JOIN (SELECT replygemid, MIN(CurrentTotal) AS MinTotal
FROM (SELECT replygemid, @runningtotal:=@runningtotal+1 AS CurrentTotal
FROM (SELECT @runningtotal := 0)Deriv1, gems 
ORDER BY replygemid) Deriv2
GROUP BY replygemid) Deriv5
ON Deriv4.replygemid = Deriv5.replygemid 
AND Deriv4.CurrentTotal < Deriv5.MinTotal + 10
WHERE gems.grade = '7'

这样做是使用子选择将序列号添加到回复(由父级排序)。它使用此子选择两次,一次获取组的最小序列号,然后再次带回具有序列号的所有行详细信息。然后将其加入以获取序列号是该 gem 的前 10 个之一的那些。

虽然我更喜欢将内容保存在单个 SQL 中,但我认为这已经到了太慢而不值得的阶段。

也许可以使用 GROUP_CONCAT 将文件详细信息添加到 gem 回复中,然后在您的代码中处理您不感兴趣的那些(即超过 10 个)

抱歉,我想不出更有用的东西

【讨论】:

  • 我没有考虑过使用动态变量来跟踪记录。它很粗糙。我在上面发布的第一个 sql 查询实际上确实正确地限制了记录,所以我认为这不会比它有优势。记录集很难使用(与 UNION 的清洁相比),但至少它可以工作。我决定继续使用它,希望性能不是问题。感谢您的建议。
猜你喜欢
  • 2018-10-15
  • 1970-01-01
  • 2016-08-12
  • 1970-01-01
  • 2017-07-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-22
  • 2011-07-04
相关资源
最近更新 更多