2009-01-14 60 views
7

我正在尋找在90天內在很多服務器上存儲來自JVM的一些JMX數據。這些數據將是統計數據,如堆大小和線程數。這意味着其中一張表格將有大約3.88億條記錄。對於擁有3億多記錄的MySQL表,有哪些優化技術?

從這些數據我建立一些圖表,所以你可以比較從Mbeans檢索到的統計數據。這意味着我將使用時間戳以一定的間隔抓取一些數據。

所以真正的問題是,有無論如何優化表或查詢,以便您可以在合理的時間內執行這些查詢?

謝謝,

約什

回答

9

有幾件事情可以做:

  1. 建立你的索引來匹配您正在運行的查詢。運行EXPLAIN查看運行的查詢的類型,並確保它們都儘可能使用索引。

  2. 分區您的表。分區是一種通過特定(聚合)鍵將大型表分成幾個小型表的技術。 MySQL在內部支持這個從ver. 5.1

  3. 如有必要,可以構建彙總表來緩存查詢中昂貴的部分。然後針對彙總表運行查詢。同樣,可以使用臨時內存表來將表格的簡化視圖存儲爲預處理階段。

2

3建議:

  1. 索引
  2. 索引
  3. 索引

P.S.對於時間戳,您可能遇到性能問題 - 取決於MySQL如何在內部處理DATETIME和TIMESTAMP,將時間戳存儲爲整數可能會更好。 (1970年以來的秒數或其他)

2

那麼,首先,我建議您使用「離線」處理來生成「圖形就緒」數據(對於大多數常見情況),而不是試圖查詢原始數據一經請求。

1

如果您使用的是MYSQL 5.1,則可以使用新功能。 但被警告他們包含大量的錯誤。

首先你應該使用索引。 如果這還不夠,可以嘗試使用分區來分割表。

如果這也行不通,您還可以嘗試負載平衡。

1

一些建議。

您可能要對這些東西運行聚合查詢,所以在將數據加載到表中之後,您應該預先聚合數據,例如按小時計算預計算總數,或按用戶或按星期,無論如何,你都會明白,並將其存儲在用於報告圖形的緩存表中。如果你能縮小你的數據集一個數量級,那麼,對你有好處!

這意味着我將使用時間戳以一定間隔抓取一些數據。

那麼這意味着您只能使用最近X天的數據?

從表中刪除舊數據可能會非常慢,如果你有幾千萬行要刪除,分區對於那個很好(只需刪除舊分區)。它還將相同時間段內的所有記錄分組在一起,因此它的緩存效率更高。

現在,如果你使用MySQL,我強烈建議使用MyISAM表。你沒有得到防碰撞或事務處理,並且鎖定是愚蠢的,但是表的大小比InnoDB小得多,這意味着它可以放入RAM中,這意味着更快的訪問。

由於大型聚合可能涉及大量相當連續的磁盤IO,因此像RAID10(或SSD)這樣的快速IO系統是一個優點。

有無論如何優化表或查詢,所以你可以在合理的時間內執行這些查詢 ?

這取決於表和查詢;不知道更多,不能給出任何建議。

如果您需要使用大型聚合和連接進行復雜的報表查詢,請記住MySQL不支持任何花哨的JOIN,哈希聚合或其他任何有用的東西,基本上它唯一能做的就是嵌套循環索引掃描在緩存的表上是好的,並且如果涉及一些隨機訪問,則在其他情況下非常殘暴。

我建議你用Postgres進行測試。對於大集合,更智能的優化器確實運行良好。

實施例:

CREATE TABLE t (id INTEGER PRIMARY KEY AUTO_INCREMENT, category INT NOT NULL, counter INT NOT NULL) ENGINE=MyISAM; 
INSERT INTO t (category, counter) SELECT n%10, n&255 FROM serie; 

(系列包含其中n = 1 .. 16000000 16M線)

MySQL Postgres  
58 s  100s  INSERT 
75s  51s  CREATE INDEX on (category,id) (useless) 
9.3s  5s   SELECT category, sum(counter) FROM t GROUP BY category; 
1.7s  0.5s  SELECT category, sum(counter) FROM t WHERE id>15000000 GROUP BY category; 

在一個簡單的查詢這樣PG是大約2-3倍更快(差異將如果涉及複雜的連接,則要大得多)。

0
  1. 解釋你的SELECT查詢
  2. LIMIT 1當獲得一個唯一的行 SELECT * FROM用戶WHERE狀態= '阿拉巴馬' //錯誤 SELECT 1 FROM用戶WHERE狀態= '阿拉巴馬' LIMIT 1

  3. 索引搜索字段 索引不僅僅是主鍵或唯一鍵。如果表格中有任何要搜索的列,則應該幾乎總是對它們進行索引。

  4. 索引和用法連接的相同列類型 如果您的應用程序包含許多JOIN查詢,則需要確保通過兩個表索引您加入的列。這會影響MySQL在內部優化連接操作的方式。

  5. 不要按ORDER BY RAND() 如果你確實需要結果中的任意行,那麼有更好的方法。當然,它需要額外的代碼,但是您可以防止隨着數據增長而出現指數級惡化的瓶頸。問題是,在對數據進行排序並給你1行之前,MySQL必須對錶中的每一行執行RAND()操作(這需要處理能力)。

  6. 使用ENUM over VARCHAR ENUM類型的列非常快速而且緊湊。它們在內部存儲爲TINYINT,但它們可以包含並顯示字符串值。

  7. 使用NOT NULL如果您可以 除非您有一個非常具體的使用NULL值的原因,否則應始終將您的列設置爲NOT NULL。 「

    」NULL列需要額外的空間來記錄它們的值是否爲NULL。對於MyISAM表,每個NULL列需要一位額外的,四捨五入到最近的字節。

  8. 將IP地址存儲爲UNSIGNED INT 在您的查詢中,您可以使用INET_ATON()將IP轉換爲整數,將INET_NTOA()反過來。 PHP中也有類似的函數,稱爲ip2long()和long2ip()。