2016-12-31 68 views
0

我有這個模式可以保存聊天消息。目前我有大約10萬行,大約5.5MB的數據。索引大小是6.5MB。當數據大小爲〜4MB時,指數大小爲〜3MB,因此它正在成倍增長優化表以減少索引大小

CREATE TABLE `messages` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `author` int(11) unsigned DEFAULT NULL, 
    `time` int(10) unsigned DEFAULT NULL, 
    `text` text, 
    `dest` int(11) unsigned DEFAULT NULL, 
    `type` tinyint(4) unsigned DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `history` (`author`,`dest`,`id`) USING BTREE, 
    KEY `messages_ibfk_1` (`dest`), 
    FULLTEXT KEY `msg` (`text`), 
    CONSTRAINT `au` FOREIGN KEY (`author`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 
    CONSTRAINT `messages_ibfk_1` FOREIGN KEY (`dest`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB AUTO_INCREMENT=105895 DEFAULT CHARSET=utf8; 

我正在運行鍼對該表和我一直試圖優化它的是,當我需要顯示分頁歷史聊天2人

SELECT id, time, text, dest, type, author 
FROM `messages` 
WHERE (
    (author = ? AND dest = ?) OR (author = ? AND dest = ?) 
) AND id <= ? ORDER BY id DESC LIMIT ?, 25 

之間的主查詢對歷史記錄的其他查詢是相同的,除了它們具有用於搜索詞或日期範圍的附加過濾器。

有什麼可以做的,以減少索引大小和保持最佳性能?

+0

爲什麼你認爲索引大小與性能有關?您的查詢運行緩慢嗎?畢竟,如果你沒有索引,那麼你會節省很多空間,但是你的查詢會慢很多,所以顯然有一個索引是一個空間性能折衷,通過索引,你我們表達了以犧牲太空爲代價的表現。 –

+0

如果MySQL爲了將來插入而在btree中留下一些未填充的空間,那麼您的索引可能會大於表本身。 –

+0

順便說一下,您可以通過存儲「user1」和「user2」而不是「author」和「dest」,按字母順序排列這兩個用戶,並使「user1」成爲第一個用戶,從而減少索引大小並提高查詢性能。第二個是「user2」。所以如果你想找到馬克和愛麗絲之間的對話,愛麗絲將永遠是「用戶1」,馬克將永遠是「用戶2」。然後,您可以添加另一列來指示「user1」是作者還是收件人。 –

回答

1

不要擔心指數的增長。這可能是一種僥倖;當然不是「指數級」。

假設的主要問題是

SELECT id, time, text, dest, type, author 
FROM `messages` 
WHERE (
    (author = ? AND dest = ?) OR (author = ? AND dest = ?) 
) AND id <= ? ORDER BY id DESC LIMIT ?, 25 

我看到三種技術,這將有助於顯著性能:更改ORUNION,處理LIMITUNION,並且不要使用分頁OFFSET

 (SELECT id, time, text, dest, type, author 
      FROM `messages` 
      WHERE author = ? -- one author & dest 
       AND dest = ? 
       AND id < ? -- where you "left off" 
      ORDER BY id DESC 
      LIMIT 25 
     ) UNION ALL 
     (SELECT id, time, text, dest, type, author 
      FROM `messages` 
      WHERE author = ? -- the other author & dest 
       AND dest = ? 
       AND id < ?  -- same as above 
      ORDER BY id DESC 
      LIMIT 25 
     ) 
     ORDER BY id DESC 
     LIMIT 25;   -- get the desired 25 from the 50 above 

Pagination discussion解釋了爲什麼OFFSET應該被刪除。它討論了其他技術,包括使用26個(在所有三個地方)而不是25個,以便您知道這是否是「最後一頁」頁面。

在第一次迭代中,AND id < ?可能會被關閉。或者(更簡單),你可以替換一個非常大的數字。

您的指數(author,dest,id)對於我的形成是最佳的。

隨着messages變得更大和/或用戶頁面進入列表更遠,這種複雜的公式將會發光。

+0

無論表格大小或頁碼如何,此表達式最多可觸及50行(加上寫入50到tmp和重新讀取50)。原始配方總是觸及大部分或全部行。 –

+0

謝謝你的回答,這是最有幫助的 - 特別是關於避免使用偏移量進行分頁的部分,我過去遇到過這個問題。然而,問題是這個指數的大小是否可以接受,以及如何減少它,因爲指數大於我的數據的IMH(noob)O看起來不合時宜 - 這就是爲什麼我不會將答案標記爲已接受的原因。 –

+0

還有一些我認爲值得指出 - 運行原始查詢從1毫秒沒有偏移返回的問題,但獲得相同的結果與50毫秒的聯合返回。我記得我在設計桌子時也測試了這一點,過去也是如此 - 'OR'多次超過'UNION'。 –