簡體   English   中英

mysql:選擇最后10條消息,每條消息最后3條回復

[英]mysql: select the last 10 messages and for each message the last 3 replies

為簡單起見,讓我們將消息表減至最少,並提供一些示例數據

message_id  reply_to    createdate
1           0           123
2           0           124
3           0           123
4           1           154
5           1           165

Reply_to是message_id,其中消息是對

所以我正在尋找一個sql語句/過程/函數/其他表設計,讓我選擇最后10條消息,對於最后3條答復中的每條,我都不介意更改表結構,甚至不保留某種記錄最后3條回復

只需選擇最后10條消息

SELECT * FROM message ORDER BY createdate LIMIT 10;

對於每個消息,答復是

SELECT * FROM message WHERE reply_to = :message_id: ORDER BY createdate LIMIT 3;

到目前為止,我的嘗試是:

  • 消息表上的三重外部聯接作為答復
  • 一個普通的聯接,但是mysql不允許聯接的限制
  • 使用HAVING COUNT(DISTINCT reply_to)<= 3,但是HAVING當然是最后評估的

我不能讓那些工作

我的最后一個選擇是,有一個單獨的表來跟蹤每條消息的最后3條回復

message_reply: message_id, r_1, r_2, r_3

然后使用觸發器更新該表,以便消息表中的新行(即回復)更新message_reply表

UPDATE message_reply SET r_3 = r_2, r_2 = r_1, r_1 = NEW.reply_to WHERE message_id = NEW.message_id

然后我可以查詢消息表中的記錄

任何人都有更好的建議甚至是有效的SQL語句?

謝謝

編輯:

添加了EXPLAIN結果

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY     <derived4>  ALL     NULL    NULL    NULL    NULL    3    
1   PRIMARY     <derived2>  ALL     NULL    NULL    NULL    NULL    10  Using where; Using join buffer
1   PRIMARY     r   eq_ref  PRIMARY,message_id,message_id_2     PRIMARY     4   func    1    
4   DERIVED     NULL    NULL    NULL    NULL    NULL    NULL    NULL    No tables used
5   UNION   NULL    NULL    NULL    NULL    NULL    NULL    NULL    No tables used
6   UNION   NULL    NULL    NULL    NULL    NULL    NULL    NULL    No tables used
NULL    UNION RESULT    <union4,5,6>    ALL     NULL    NULL    NULL    NULL    NULL     
2   DERIVED     m   ALL     NULL    NULL    NULL    NULL    299727   
3   DEPENDENT SUBQUERY  r   ref     reply_to,reply_to_2     reply_to_2  4   testv4.m.message_id     29973    

編輯2:

好吧,我嘗試了message_reply表方法,這也是我所做的

建立表格:

message_reply: message_id, r_1, r_2, r_3

建立觸發器:

DELIMITER |
CREATE TRIGGER i_message AFTER INSERT ON message
  FOR EACH ROW BEGIN
    IF NEW.reply_to THEN
        INSERT INTO message_replies (message_id, r_1) VALUES (NEW.reply_to, NEW.message_id)
        ON DUPLICATE KEY UPDATE r_3 = r_2, r_2 = r_1, r_1 = NEW.message_id;
    ELSE
        INSERT INTO message_replies (message_id) VALUES (NEW.message_id);
    END IF;
  END;
|
DELIMITER ;

並選擇以下消息:

SELECT m.*,r1.*,r2.*,r3.* FROM message_replies mr
LEFT JOIN message m ON m.message_id = mr.message_id
LEFT JOIN message r1 ON r1.message_id = mr.r_1
LEFT JOIN message r2 ON r2.message_id = mr.r_2
LEFT JOIN message r3 ON r3.message_id = mr.r_3

當然,對觸發器進行預處理對我來說這是最快的方法。

用更多的100k插入集進行測試,以查看觸發器對性能的影響,處理100k行花費了0.4秒以上的時間,因為沒有插入時間的情況下總插入時間約為12秒(在myIsam表上)

一個工作示例:

編輯-(請參閱早期查詢的修訂)

全表創建和說明計划
注意:表“ datetable”僅包含約10年的所有日期。 它僅用於生成行。

drop table if exists messages;
create table messages (
   message_id int primary key, reply_to int, createdate datetime, index(reply_to));

insert into messages 
select @n:=@n+1, floor((100000 - @n) / 10), a.thedate
from (select @n:=0) n
cross join datetable a
cross join datetable b
limit 1000000;

上面的消息產生了1m條消息,並給出了一些有效的回復。 查詢:

select m1.message_id, m1.reply_to, m1.createdate, N.N, r.*
from
(
    select m.*, (
         select group_concat(r.message_id order by createdate)
          from messages r
        where r.reply_to = m.message_id) replies
     from messages m
     order by m.message_id
    limit 10
) m1
inner join ( # this union-all query controls how many replies per message
    select 1 N union all
     select 2 union all
     select 3) N
  on (m1.replies is null and N=1) or (N <= length(m1.replies)-length(replace(m1.replies,',','')))
left join messages r
  on r.message_id = substring_index(substring_index(m1.replies, ',', N), ',', -1)

時間:0.078秒

解釋計划

id     select_type         table        type      possible_keys    key      key_len ref                rows    Extra
1      PRIMARY             <derived4>   ALL      (NULL)            (NULL)   (NULL)  (NULL)             3    
1      PRIMARY             <derived2>   ALL      (NULL)            (NULL)   (NULL)  (NULL)             10      Using where
1      PRIMARY             r            eq_ref   PRIMARY           PRIMARY  4       func               1    
4      DERIVED             (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
5      UNION               (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
6      UNION               (NULL)       (NULL)   (NULL)            (NULL)   (NULL)  (NULL)             (NULL)  No tables used
(NULL) UNION RESULT        <union4,5,6> ALL      (NULL)            (NULL)   (NULL)  (NULL)             (NULL)    
2      DERIVED             m            index    (NULL)            PRIMARY  4       (NULL)             1000301    
3      DEPENDENT SUBQUERY  r            ref      reply_to          reply_to 5       test.m.message_id  5       Using where

我建議您建立額外的表,並使其按照需要的步驟執行。 有時,要使答案形象化,您需要采取其他步驟。 最后,您可以將SQL編譯為一個嵌套語句。

注意:此答案為比較OMG的評論提供了有用的信息,因此,即使需要刪除它,也請稍等片刻。

OMG:檢查mysql和“ greatest-n-per-group”標簽的配對-請求很常見。 OMG:然后訪問問題並有禮貌地告知是否回答。

我遵循了OMG的指示,這就是我的想法
https://stackoverflow.com/questions/tagged/greatest-n-per-group+mysql

  1. SQL-僅針對每種類型給我3個匹配
  2. mySQL返回每個類別的前5名
  3. MySQL SELECT n記錄基於GROUP BY

您可能會誤解了該問題,因為結果的第一頁中的3個看起來最相似(其中2個是我的答案),該問題涉及整個表的一個維度(每個類別的前n個)。 解決方案始終按表順序在表中提供row_number ALL條記錄。

將其與為問題域top-n-category -> top-m-per-category為該問題提供的優化答案進行比較,您將意識到此問題是一個不同的問題。

無需visit the questions and courteously inform if not answer因為

  1. 這些問題的答案是有效的
  2. 這個問題的答案是有效的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM