2011-04-24 53 views
10

我發現了一個類似的線程,但它並沒有真正捕捉到我想要問的內容 - 所以我創建了一個新的線程。SQL中JOIN的代價如何?和/或,性能和正常化之間的折衷是什麼?

我知道在規範化和性能之間有一個折衷,我想知道繪製該線的最佳做法是什麼?在我的特殊情況下,我有一個消息系統,它有三個不同的表:message_threads(總括消息持有者),messages_recipients(涉及的人)和messages_messages(實際消息+時間戳)。

爲了返回「收件箱」視圖,我必須將messages_threads表,users表和users圖表添加到messages_recipients表中,以便獲取信息以填充視圖(配置文件圖片,發件人名稱,線程ID)...並且我還添加了一個連接到消息以檢索最後一條消息中的文本,以便向用戶顯示最後一條消息的「預覽」。

我的問題是:在SQL中JOIN成本是如何代價的?例如,我可以在messages_threads表中的一個名爲「sendername」的字段下存儲發件人的名稱(我必須離開用戶的聯接來檢索) - 但就規範化而言,我總是教會避免數據冗餘?

你在哪裏畫線?或者我高估了性能如何阻礙SQL連接?

回答

20

最佳做法是總是從3NF開始,然後只在發現特定性能問題時才考慮非規範化。

性能只是一個你必須處理的數據庫問題。通過複製數據,可能會導致數據庫中存在不一致的數據,從而導致關係數據庫的一個核心原則(即CACIDa中無效。

是的,連接有成本,沒有得到解決。但是,成本通常比您想象的要低很多,並且通常可能會受到網絡傳輸時間等其他因素的影響。通過確保相關列正確編制索引,您可以避免很多成本。

而且,記住優化的口頭禪:措施,別猜!在類似生產的環境中測量。定期測量(和調整) - 如果您的模式和數據永遠不會改變(非常不可能),則優化只是一個設定而忘記的操作。


一個)復歸性能通常可以由通過使用觸發器來保持一致性安全。這當然會減慢你的更新速度,但仍然可以讓你的選擇速度更快。

+0

謝謝pax,你是對的 - 我應該堅持ACID。感謝您清除我,我閱讀了一篇關於大規模網站反規範化的文章,並開始質疑我的結構。 – Walker 2011-04-24 22:47:00

+3

@Walker,非規範化_is_有時是一個可行的選擇。你只需要確保它不僅僅會阻礙:-)與大多數生活一樣,這也是一種折衷。 – paxdiablo 2011-04-24 22:52:48

3

我不會擔心一個額外的連接。根據我的經驗,當您加入大型數據集時,來自連接的巨大性能損失就會來臨。據推測,你的消息視圖將顯示20-100行的頂部。

但有一件事 - 如果您不需要左連接,只需使用常規連接即可。左連接和普通連接需要額外的大量時間。

如果你真的好奇,你可以設置一個基準。 PHPMyAdmin會告訴你一個查詢需要多長時間才能運行;你可以檢查有沒有最後加入的時間。 (請注意,所有phpmyadmin select查詢都是有限的,所以如果您選擇了超過20行的話,您可以期待更長的執行時間)。

+0

phpMyAdmin不適合這類工作。你應該使用像EMS MySQL Manager,Navicat for MySQL或其他的桌面工具。 – kubal5003 2011-04-24 22:35:14

+0

如果您需要來自兩個大型數據集的數據,JOINS通常是獲取數據的最有效方式。 – dkretz 2011-04-24 22:39:47

+0

我有Sequel Pro,它在測試性能方面效果很好 - 我不知道LEFT JOIN的成本更高,然後加入 - 儘管如此,我一定會返回並在我的代碼中替換大量的LEFT JOIN語句。 – Walker 2011-04-24 22:47:47

3

這個問題沒有簡單的答案。根據可用指標,記錄數量和許多其他因素,加入成本差異很大。 MySQL中的AFAIR至少有一些連接策略,從最好到最差的情況進行排序。

實際上,您需要根據有關數據安全性的一般規則制定模式 - 所以在需要時將數據庫標準化。

反正規化只有當你有一個真正的性能問題並且沒有其他解決方法(例如添加索引,更改參數,重寫查詢等)時纔會發生,並且應該基於深度分析問題。

2

根據我的經驗,額外的JOIN段在查詢中的影響通常不會造成或中斷應用程序。索引,避免子查詢和有時避免LEFT JOIN語句會產生最大的影響。

正如Sam Dufel提到的那樣,建立一個基準來確定您使用的左連接是否應該被解決。生成一堆虛擬數據以查看它是否隨JOIN中的記錄數增加而縮放也可能很有用。

1

連接是提高查詢效率的策略。與另一種迴應相反,外部連接與我已有機會編寫文本的每個產品(包括MySQL(兩種主要引擎),SQL Server,Sybase和Oracle)的內部連接一樣有效。

要避免的是子查詢(主要是相關的子查詢),它通常用作替代方法。

1

總是喜歡正常化。對我來說,非規範化STILL得到這種關注是令人震驚的。

NORMALIZE - 這是數據庫引擎調整的。

+0

感謝蘭迪,我質疑它的唯一原因是閱讀有關Twitter的反規範化。 – Walker 2011-04-24 22:46:08

+1

是的 - 我可能反應過度了。但是直到你證明你的系統正常化了,你纔會真正考慮它。 – Randy 2011-04-24 23:29:02

1

回答關於如何進行昂貴加入的問題是不可能的或有用的。

連接只是SQL查詢中的一個命令,數據庫對該連接做的事情完全不同。查詢中昂貴的東西就像表掃描一樣,數據庫必須讀取整個表來定位一些數據。在有有用索引的表上有十個連接的查詢可能比沒有任何有用索引的單個表上的查詢快得多。

查詢中的三個或四個連接肯定沒有任何理由去規格化表以嘗試提高性能。作爲比較;對於我們的網站,我們使用的是非標準化表格進行讀取,因爲我們需要大約40個連接來收集我們需要的數據。

相關問題