2010-09-28 260 views
1

好吧,在這一點上,我很困惑如何以有效的方式構建我的分頁系統。問題是系統不是典型的,並且沒有定期間隔,例如每頁10個。問題是,消息可以有回覆,並因此共享相同的reply_chunk_id(reply_id)。我不想讓消息被切斷,但這樣做似乎越來越複雜。需要幫助與複雜的mysql分頁查詢邏輯

我的初始查詢檢索消息是這樣的,它檢索消息作爲一個分組,無論在表中的答覆,它會出來與相同的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

只是你的一個選擇,我知道這不是一個答案,但有時在JavaScript中構建分頁可能是一個令人滿意的努力。 – 2010-09-28 22:05:06

+0

是真實的,但我仍然需要一種顯示每個頁面的消息的方式,其中數字四捨五入。我目前正在合併一個實時刷新消息的jQuery Ajax調用,但我不熟練使用javascript。 – Scarface 2010-09-28 22:15:00

+0

另外,如果在javascript中完成,我仍然必須先檢索所有消息,然後再對它們進行處理,這將對服務器造成負擔。不幸的是,我想到的方式似乎更加重要,但我希望有一個更好的方法或邏輯建議 – Scarface 2010-09-28 22:23:07

回答

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對查詢一些腳本邏輯的邏輯。

+0

Wrikken,讓我只是說,非常感謝你發佈答案,過去沒有人遇到過這個問題我認爲沒有人會回答我,但是你的查詢返回0行,這是不正確的。我會試着調整它,並看看它來進一步瞭解它。如果您在我之前發現任何錯誤,請告訴我。再次感謝。 – Scarface 2010-09-29 03:23:26

+0

有一段時間來測試和更好,我使用的testdata在http://pastebin.com/Q49yJc7s – Wrikken 2010-09-29 23:27:51

+0

再次感謝wrikken – Scarface 2010-10-01 21:26:30