【问题标题】:Need help with complex mysql pagination query logic在复杂的mysql分页查询逻辑方面需要帮助
【发布时间】:2010-09-30 07:21:01
【问题描述】:

好的,在这一点上,我很困惑如何以有效的方式构建我的分页系统。问题是系统不是典型的,不会定期发送,例如每页 10 个。问题是,消息可以有回复,因此共享相同的回复块 ID (reply_id)。我不希望消息被切断,但这样做似乎越来越复杂。

我检索消息的初始查询是这样的,无论回复在表中的哪个位置,它都会将消息作为一个分组来检索,它会根据时间戳按降序依次与具有相同回复块 ID 的相应消息分组

SELECT m.timestamp, m.user, m.message, g.grp_timestamp,m.reply_chunk_id
  FROM shoutbox AS m JOIN
       (SELECT reply_chunk_id, MIN(timestamp) AS grp_timestamp
          FROM shoutbox
         GROUP BY reply_chunk_id) AS g ON m.reply_chunk_id = g.reply_chunk_id
 WHERE m.topic_id = ? 
 ORDER BY g.grp_timestamp DESC, g.reply_chunk_id, m.timestamp DESC limit ?, ?

我在想我需要另一个查询来检索此查询的限制参数,因为页面不会定期进入,因此需要唯一的起点和终点,具体取决于您选择的页面。我正在考虑选择一个限制,比如说 $limit 10 作为示例,然后转到最接近的四舍五入的消息数。例如,如果您收到第 10 条消息,并且该组还有 2 条回复,您将检索到 12 条消息。

我遇到的问题是构造此限制检索查询的逻辑。我必须以某种方式从该主题的第一条消息开始,计算所有回复,然后转到第二条,计算所有回复,直到达到四舍五入的数字,然后输出。

真正的麻烦是说你要换页,你会如何转移到上一页的终点,或者你可能跳过一页直接从第1-3页开始.答案是你不能,所以你每次都必须从该主题的第一条消息开始,计算所有回复,继续对每条消息做同样的事情,直到你达到四舍五入的数字,以某种方式表明你已经通过了第一页,并继续前进,直到您到达所需的页面消息。我真的不知道该怎么做,或者这是否是最好的方法,所以任何帮助或建议都非常感谢。

餐桌设计

CREATE TABLE IF NOT EXISTS `shoutbox` (
  `id` int(5) NOT NULL AUTO_INCREMENT,
  `timestamp` int(11) NOT NULL,
  `user` varchar(25) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL 
         DEFAULT 'anonimous',
  `message` varchar(2000) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  `topic_id` varchar(35) NOT NULL,
  `reply_chunk_id` varchar(35) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

【问题讨论】:

  • 只是你的一个选择,我知道这不是一个答案,但有时在 javascript 中构建分页可能是一项令人满意的工作。
  • 是的,但我仍然需要一种方法来显示每个页面的消息,其中数字以某种方式四舍五入。我目前打算合并一个实时刷新消息的jquery ajax调用,但我对javascript不是很精通。
  • 另外,如果在 javascript 中完成,我仍然必须先检索所有消息,然后再运行它们,这会对服务器造成负担。不幸的是,我的想法似乎更加费力,但我希望能提出更好的方法或逻辑

标签: sql mysql pagination


【解决方案1】:

编辑:有时间测试,新的检查单查询解决方案

SELECT timestamp, user, message, grp_timestamp,reply_chunk_id
FROM (
  SELECT totalresult.*,
    @page := IF(
        (
          @subcounter >= @perpage                    -- if we have more then @perpage
          AND
          reply_chunk_id != @old_chunk_id            -- AND we are on a reply_chunk border
        )
        OR
        (
          @subcounter >= @absolutemax                -- the upper maximum is reached
        )
        OR 
        (
          (@subcounter + grp_messagecount > @absolutemax) -- next replychunk would put us over the top
          AND 
          (grp_messagecount <= @absolutemax)              -- next replyhunk would fit in a single pagenumber
          AND
          (@subcounter >= @allowprematurebreak)           -- and we have enough items to qualify for a page
        ),
      @page + 1 + (@subcounter:=0),                 -- increment page and reset counter
      @page) as page,                               -- otherwise keep the same @page
    @subcounter := @subcounter + 1      as counter, -- increment counter
    @old_chunk_id := reply_chunk_id as reply_chunk  -- store previous reply chunk
  FROM (
    SELECT 
        m.timestamp, m.user, m.message, g.grp_timestamp,m.reply_chunk_id, g.grp_messagecount
    FROM shoutbox AS m
    JOIN (
          SELECT
            reply_chunk_id,
            MIN(timestamp) AS grp_timestamp,
            COUNT(*)       AS grp_messagecount
          FROM shoutbox
          GROUP BY reply_chunk_id
    ) AS g ON m.reply_chunk_id = g.reply_chunk_id
    WHERE m.topic_id = ? 
    ORDER BY g.grp_timestamp DESC, g.reply_chunk_id, m.timestamp DESC
  ) AS totalresult
  JOIN (
    SELECT
      @page                :=0,  -- the page number / counter
      @old_chunck_id       :=0,  -- placeholder for old reply_chunk so we can detect boundaries
      @subcounter          :=0,  -- counter for number of actual messages
      @perpage             :=10, -- preferred amount of messages per page
      @absolutemax         :=20, -- allow breaking in reply_chunk if absolutemax is reached
      @allowprematurebreak :=5   -- minimum of messages per page, used if we can let the 
                                 -- next chunk see whole on the next page
  ) AS void
) AS paginatedresult
WHERE page = <pagenumber>

我添加了一些设置作为变量,以便于参数绑定更容易且更具可读性。关于性能:对它进行基准测试,它可能做得很好(当然因为它受到主题的限制)。如果没有,您的解决方案将获取此内部子查询的输出:

          SELECT
            reply_chunk_id,
            MIN(timestamp) AS grp_timestamp,
            COUNT(*)       AS grp_messagecount
          FROM shoutbox
          GROUP BY reply_chunk_id

并将确定在哪里中断的逻辑移动到一些脚本逻辑中,该逻辑决定要查询哪个reply_chunk_id。

【讨论】:

  • Wrikken,我只想说,非常感谢您发布答案,过去没有人解决过这个问题,我认为没有人会回答我,但是您的查询返回 0 行这是不正确的.我将尝试对其进行调整并查看它以进一步了解它。如果您在我之前发现任何错误,请告诉我。再次感谢。
  • 有一些时间来测试和改进它,我在pastebin.com/Q49yJc7s使用的测试数据
猜你喜欢
  • 2013-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 2014-07-08
相关资源
最近更新 更多