2013-01-14 23 views
3

我爲我的用戶創建了一個私人消息系統,這是我在php中用mysql後端創建的。系統刪除舊消息,但通常會保留超過500,000條消息。目前,所有的數據都包含在一個表:將私人消息「body」字段存儲在單獨的表中以獲得速度增益

message_table 
    message_id (int 11) 
    message_from_id (int 11) 
    message_to_id (int 11) 
    message_timestamp (int 11) 
    message_subject (varchar 50) 
    message_text (text) 

大部分的消息都非常短,所以我考慮了系統更改爲:

message_table 
    message_id (int 11) 
    message_from_id (int 11) 
    message_to_id (int 11) 
    message_timestamp (int 11) 
    message_subject (varchar 50) 
    message_short_body (varchar 50) 
    message_text_id (int 11) 

text_table 
    text_id (int 11) 
    text_body (text) 

那麼,如果一個短消息輸入時將在'message_short_body'下輸入,如果更長的話將被添加到'text_table'並且'text_id'被存儲爲'message_text_id'。如果消息是訪問我會再有這樣的事情:

SELECT * FROM message_table LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id IF message_table.message_text_id != 0 WHERE message_table.message_to_id = $user_id 

我補充說:「如果message_table.message_text_id!= 0」,不知道這樣的事情是可能的。

作爲一般規則,可以判斷這是否會減少數據庫/加速查詢的大小?

+0

一般規則是:當您發現瓶頸(是否?)時優化並測試工作負載的變化。我的意思是,使用'INSERT INTO SELECT'將這個東西複製到新結構中需要幾秒鐘的時間。你可以在你寫這個問題的同時測試選擇性能。 – Prinzhorn

回答

2

我加了「IF message_table.message_text_id!= 0" ,不知道這樣的事情是可能的。

除非實際上是text_id = 0排在text_table,也沒有必要這麼做。簡單地忽略IF和使用以下查詢:

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body, 
     … 
FROM message_table 
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id 
WHERE message_table.message_to_id = $user_id 

在性能方面,它可能是發動機可以更有效地優化的事情,如果你把你的情況向加盟條件:

SELECT IFNULL(text_table.text_body, message_table.message_short_body) AS body, 
     … 
FROM message_table 
LEFT JOIN text_table ON text_table.text_id = message_table.message_text_id 
        AND message_table.message_text_id != 0 
WHERE message_table.message_to_id = $user_id 

您還可以使用子查詢嘗試的方法:

SELECT IF(message_text_id = 0, message_short_body, (
    SELECT text_table.message_short_body 
    FROM text_table 
    WHERE text_table.text_id = message_table.message_text_id)) AS body, 
     … 
FROM message_table 
WHERE message_table.message_to_id = $user_id 

這樣做是否需要沒有不執行的text_table搜索的好處,但在一起久了每種情況下執行一個單獨的查詢的缺點信息。我期望上述查詢優越,但我不確定。

作爲一般規則,可以判斷這是否會減少數據庫/加速查詢的大小?

您必須進行基準測試,因爲它取決於用例。如果大多數查詢從文本以外的字段中檢索數據,那麼較小的表將使這些查詢更快,從而獲得性能提升。另一方面,如果你通常希望身體與其餘的消息一致,那麼你可能最終會得到更糟糕的表現。

您還應該使用基準來區分上述不同的備選方案。

就數據庫的大小而言,您可能會看到一個增加:文本數據的存儲需求大致相同,但額外表的索引會花費您的時間。

我想如果這是我的架構,我就把你的message_text_id,而是具有與message_tabletext_table比賽的主鍵。即每個密鑰只出現在消息表中或兩個表中,而具有相同密鑰的行則屬於同一行。在這些情況下,郵件是否在另一個表中可以通過將message_table.message_short_body設置爲NULL進行編碼。

0

試試這個:

SELECT *, IFNULL(tt.text_body, mt.message_short_body) textBody 
FROM message_table mt 
LEFT JOIN text_table tt ON tt.text_id = mt.message_text_id 
WHERE mt.message_to_id = $user_id; 
+1

您是否認爲在單獨的表中放置較大的消息會加速查詢? – RebDev

0

我說,不知道,如果這樣的事情是可能的 「IF message_table.message_text_id!= 0」。

你正在尋找的查詢是這樣的:

SELECT 
    IFNULL(t.text, m.short_text) AS text 
    -- other columns may follow 
FROM messages2 m 
LEFT JOIN texts t on m.text_id = t.id 
WHERE to_id = A_USER_ID 

一般情況下,纔有可能知道這是否會降低數據庫的大小/加快查詢速度?

是的,這是可能的!人們至少可以測試它。我已經做到了。我創建了一個包含500.000個條目的消息表的測試場景。他們每10人都有一個長文本。消息from_id和to_id是從50個用戶中隨機選擇的。

1部分:速度

的第二次嘗試,使用單獨的文本表,會給BIGGGGGG加快。第一次嘗試的平均查詢時間爲〜1.6秒。第二隻〜0.28秒!!!!

要回答這個問題:是的,它更快! :)

2部分:數據庫大小

數據庫作爲一個可能已經被預期將小幅增加的大小。從文本中附加的索引,讓我的數據庫增長約〜10%

結論:貯存於單獨的表大的文本是一個主意。在你的情況下,它會將查詢性能提高80%,磁盤成本稍微增加約10%。

+0

如果message_text_id == 0它將填充爲null,或者它會檢查text_table以查看是否存在text_id 0?就好像它是第二個不會減慢查詢速度的東西? – RebDev

+0

是的,使用LEFT JOIN時會檢查第二張桌子。我不確定,但是當message_text_id而不是'0'使用'NULL'時,它可能沒有被檢查 – hek2mgl

+0

運氣不錯,引擎會知道(從索引緩存的數據)最小的'text_id'更大比零,並從中推斷,它不會找到匹配的查詢。 – MvG