2008-08-15 62 views
19

我有一個正常化的訂單數據的大型數據庫,查詢報告變得非常緩慢。我在報告中使用的許多查詢加入了5或6個表格,並且必須檢查數十或數十萬行。什麼是非規範化mysql數據庫的好方法?

有很多查詢,大多數都已儘可能優化以減少服務器負載並提高速度。我認爲是時候開始以非規範化格式保存數據的副本了。

任何想法的方法?我應該從幾個最糟糕的問題開始並從那裏出發?

回答

10

我知道更多關於mssql的信息,但我不認爲你正在談論的連接數或行數會導致你在正確索引的地方出現太多問題。你有沒有分析查詢計劃,看看你是否錯過了?

http://dev.mysql.com/doc/refman/5.0/en/explain.html

話雖這麼說,一旦你satisifed與指標,並已用盡所有其他途徑,去正常化可能是正確的答案。如果您只有一個或兩個查詢是問題,那麼手動方法可能是適當的,而某種數據倉庫工具可能更適合創建開發數據立方體的平臺。

這裏有一個網站,我發現,關於這個問題倒是:

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

下面是一個簡單的技術,你可以用它來保持反規範化查詢簡單,如果你只是做了幾個在同一時間(而且我不會替換您的OLTP表格,只是爲報告目的創建一個新表格)。比方說,你有這個疑問在你的應用程序:

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1 

您可以創建一個非規範化表和幾乎相同的查詢填充:

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided) 

注意下劃線匹配您使用

表的別名
insert tbl_ab select a.id, a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything 

然後要修復您的應用程序以使用新的非規格化表格,請切換下劃線的點。

select a_name as name, b_address as address 
from tbl_ab where a_id = 1; 

對於巨大的查詢,這樣可以節省大量的時間並明確了數據的來源,你可以重新使用已有的查詢。

請記住,我只是提倡這是最後的手段。我敢打賭,有幾個索引可以幫助你。並且,當您解除規範化時,請不要忘記考慮磁盤上的額外空間,並確定何時運行查詢來填充新表。這可能應該是在晚上,或者活動不足的時候。而且該表中的數據當然不會完全保持最新。

[又一個編輯]不要忘了你創建的新表也需要編入索引!好處是你可以索引你的內容,而不用擔心更新鎖爭用,因爲除了你的批量插入之外,表只會看到選擇。

1

我知道這是有點切線,但你有沒有試過看看是否有更多的索引可以添加?

我沒有太多的數據庫背景,但我最近在使用數據庫,我發現很多查詢都可以通過添加索引來改進。

我們正在使用DB2,並且有一個叫DB2EXPLN和db2advis命令時,首先會顯示是否正在使用表掃描VS索引掃描,而第二個會建議你可以添加到提高性能指標。我敢肯定,MySQL有類似的工具...

反正,如果這是你還沒有考慮的事情,它一直在幫助我很多...但如果你已經走了這條路線,那麼我想這不是你要找的。

另一種可能性是「物化視圖」(或者他們在DB2中稱之爲),它允許您指定一個基本上由多個表中的部分構建的表。因此,您可以提供此視圖來訪問數據,而不是對實際列進行標準化,但我不知道這是否對插入/更新/刪除有嚴重的性能影響(但如果它是「物化」的,那麼它應該有助於選擇,因爲這些值是分開存儲的)。

1

MySQL 5確實支持views,這在這種情況下可能會有幫助。這聽起來像你已經做了很多優化,但是如果不是的話,你可以使用MySQL的EXPLAIN語法來查看實際正在使用的索引以及減慢查詢的速度。至於對數據進行規範化(無論您是使用視圖還是僅以更高效的方式複製數據),我認爲從最慢的查詢開始並按照您的方式進行操作是一種很好的方法。

0

您可能還想考慮選擇臨時表,然後在該臨時表上執行查詢。這樣可以避免需要重新加入您發佈的每個查詢的表格(當然,假設您可以使用臨時表格進行大量查詢)。這基本上給了你非規範化的數據,但是如果你只是在做選擇調用,那麼不用擔心數據的一致性。

2

根據其他一些評論,我肯定會看看你的索引。

我今年早些時候在MySQL數據庫中發現的一件事是組合索引的力量。例如,如果您要報告日期範圍內的訂單號,則訂單號和訂單日期列上的複合索引可能會有所幫助。我相信MySQL只能使用一個索引進行查詢,所以如果你在訂單號和訂單日期上只有單獨的索引,那麼它只能決定使用它們中的一個。使用EXPLAIN命令可以幫助確定這一點。

爲了給出具有良好索引(包括衆多複合索引)的性能指標,我可以在我們的數據庫中運行查詢連接3個表並在大多數情況下獲得幾乎即時的結果。對於更復雜的報告,大多數查詢在10秒內運行。這3張表格分別有3300萬,110萬和140萬行。請注意,我們已經對這些數據進行了標準化處理,以加快對數據庫最常見的查詢速度。

有關表格和報告查詢類型的更多信息可能會提供更多建議。

0

除了我之前的回答,我們在某些情況下采取的另一種方法是將關鍵報告數據存儲在單獨的彙總表中。有些報告查詢即使在非規格化和優化之後也會變得很慢,我們發現在整個月內創建表並存儲運行總計或摘要信息時,月末報告的速度也會更快。

我們發現這種方法很容易實現,因爲它不會破壞已經工作的任何東西 - 它只是在某些點插入額外的數據庫。

0

我一直在玩複合索引,並看到了一些真正的好處......也許我會設置一些測試,看看是否可以救我在這裏..至少再長一點。