好的,我对如何以有效的方式构建我的分页系统感到很困惑。问题是系统不典型,不会定期进行,例如每页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 ;
答案 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。