2011-03-22 66 views
0

我有以下表格:需要一個數據庫設計諮詢 - 查詢與其他列

Customer(customer_id) - 1000 rows (1000 customers) 
Invoice(invoice_id, customer_id) - 1000000 rows (1000 invoices per customer) 
Charge(charge_id, invoice_id, charge_amount) - 20000000 rows (20 charges per invoice) 

現在,我想產生一個客戶的發票與它的總電量。 結果表看起來是這樣的:

Customer_name | invoice_id | charge_total 
    test    1   $1000 
    test    2   $1200 
    test    3   $900 
    ...  

我的問題是,什麼是數據庫設計的這種情況下,最好的做法是什麼? 我在思考以下兩個選項:

  1. 只需在查詢中運行所有內容?
  2. 在發票表中添加「charge_total」欄目,以節省查詢處理時間(快20倍)

謝謝大家!

回答

5

有兩種方法可以查看此問題。數據庫純粹主義者會說派生或計算的數據是多餘的,違反了第三範式。這是正在編輯數據的交易系統中的一個問題,因爲規範化可以防止您陷入自我衝突數據的陷阱。另一方面,有一種實際的觀點認爲,一次寫入並且從不更新的數據不會被更新和刪除異常,因此冗餘會佔用磁盤空間,但不是風險。

作爲一項規則,我總是首先設計數據庫進行規範化處理,然後在仔細研究競爭風險之後,在有限的基礎上引入冗餘。

+0

這顯然是一個「宗教戰爭」類型的問題,但我不同意你的主張,即需要很高的障礙。規範化的規則不是聖經的,它們是爲了避免人們經常犯的常見的愚蠢的錯誤,而這些錯誤往往會讓他們陷入更多的困境。如果你瞭解經驗法則並根據這些優點評估情況,那麼經驗法則本身就不再有用了。 – 2011-03-22 15:37:08

+0

這是我正在尋找的答案。 是的,我會等到我遇到性能問題。 謝謝。 – m0dE 2011-03-24 14:22:28

-1

製作charge_totalinvoice表中的計算列可能是我能想到的最簡單的方法。每次運行查詢以獲取值時,都可以節省您的計算時間,我假設更頻繁地添加費用。

+1

-1。在不知道性能要求的情況下優化是純粹的惡魔 – 2011-03-22 15:26:12

-3

現在的磁盤空間很便宜,所以你不必擔心大小。如果額外的列改善了性能,那麼就去吧。

+1

-1。在不知道性能要求的情況下優化是純粹的惡魔 – 2011-03-22 15:25:45

+0

實際上沒有提高代碼的性能表示懶惰。這個問題意味着可能會提出一個新的專欄,或者從任何角度來看,都不能提高性能,這是一個不錯的選擇。雖然更容易批評,然後實際回覆一個有用的答案:) – 2011-03-22 15:35:33

+1

恕我直言,不提高性能不需要更好的性能的代碼是*正確的懶惰類型*。就數據庫設計而言,就我的經驗而言,冗餘數據有很高的風險,遲早會導致問題。 – 2011-03-22 15:46:38

0

這個決定歸結爲用戶的速度與數據庫中額外的複雜性之間的折衷,這使得您的代碼更容易出錯。這讓我想起了這個討論:

https://stackoverflow.com/questions/211414/is-premature-optimization-really-the-root-of-all-evil

在你的情況,因爲你已經做了性能測試,我覺得非規範化的數據庫就像你的建議是一個很好的事情。

+1

我不相信他已經完成了性能測試。他只是猜測。 – 2011-03-22 15:27:52

+1

-1對於「非規範化」,需要有一個非常高的障礙。我不認爲OP說「快20倍」的事實意味着他實際上已經完成了性能測試,只是他正在做出性能*假設*。 – 2011-03-22 15:32:29

+0

我的不好......我從他的「20倍快」的陳述中推斷出他實際上已經完成了性能測試。我可以看到你現在從哪裏來。如果這不是一個猜測,我的答案仍然值得贊成嗎? – Spike 2011-03-22 16:06:38

0

你想記住的一件事是數據改變的頻率會影響「charge_total」的值嗎?例如,如果某件物品退回,那麼該收費是否會在稍後的日期將發票取走?如果事情經常發生變化,則必須記住讓這些更改事件負責更新「charge_total」字段的開銷。

1

這是很難回答 - 你知道你有一個性能問題?我不會優化,除非我真的,真的必須。 即使如此,我會考慮一個「發票存檔」表來保存計算值。從邏輯上講,計算摘要並將它們存儲在表格中以反映實際開具發票的金額(包括稅金,運費等)沒有任何問題。這意味着您可以存儲發票數據的存檔版本而無需擔心。

我不想將它存儲在主「發票」表中,除非發票是不可變的 - 您創建它,並且從創建它的那一刻起,任何東西都不會改變。如果您有一個預先創建發票並隨時間添加項目的業務流程,則這不起作用。

0

首先,您應該檢查沒有額外列的性能是否足夠您的情況。如果不是,那麼,而不是(!)之前,你應該檢查你的「20倍快」猜測是否真的是正確的。嘗試將charge_total的視圖添加到數據庫,並測試數據庫系統如何處理該視圖。我不太瞭解MySql,但只要源數據沒有變化,一些現代數據庫系統就可以對視圖數據進行內部緩存。

當你這樣做了,並且你確定附加列charge_total是你真正遇到的問題的解決方案,那麼你應該確保這些冗餘數據保持一致。您可以在數據庫端(使用觸發器)或在客戶端執行此操作 - 當您有一個並且只有一個進程在您的控制下更改charges表時。