需要有关复杂的mysql分页查询逻辑的帮助

时间:2010-09-28 21:57:53

标签: sql mysql pagination

好的,我对如何以有效的方式构建我的分页系统感到很困惑。问题是系统不典型,不会定期进行,例如每页10次。问题是,消息可以有回复,因此共享相同的reply_chunk_id(reply_id)。我不希望消息被切断,但这样做似乎越来越复杂。

我检索邮件的初始查询是这样的,它将邮件作为分组检索,无论表中的回复在何处,它都会根据时间戳以降序顺序与相应的reply_chunk_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 ?, ?

我原以为我需要另一个查询来检索此查询的限制参数,因为页面不会定期进行,因此根据您选择的页面需要唯一的起点和终点。我正在考虑选择一个限制,例如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 ;

1 个答案:

答案 0 :(得分: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>

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

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

移动确定在哪里进入某些脚本逻辑的逻辑,该脚本逻辑决定要查询哪个reply_chunk_id。