我正在尋找在90天內在很多服務器上存儲來自JVM的一些JMX數據。這些數據將是統計數據,如堆大小和線程數。這意味着其中一張表格將有大約3.88億條記錄。對於擁有3億多記錄的MySQL表,有哪些優化技術?
從這些數據我建立一些圖表,所以你可以比較從Mbeans檢索到的統計數據。這意味着我將使用時間戳以一定的間隔抓取一些數據。
所以真正的問題是,有無論如何優化表或查詢,以便您可以在合理的時間內執行這些查詢?
謝謝,
約什
我正在尋找在90天內在很多服務器上存儲來自JVM的一些JMX數據。這些數據將是統計數據,如堆大小和線程數。這意味着其中一張表格將有大約3.88億條記錄。對於擁有3億多記錄的MySQL表,有哪些優化技術?
從這些數據我建立一些圖表,所以你可以比較從Mbeans檢索到的統計數據。這意味着我將使用時間戳以一定的間隔抓取一些數據。
所以真正的問題是,有無論如何優化表或查詢,以便您可以在合理的時間內執行這些查詢?
謝謝,
約什
3建議:
P.S.對於時間戳,您可能遇到性能問題 - 取決於MySQL如何在內部處理DATETIME和TIMESTAMP,將時間戳存儲爲整數可能會更好。 (1970年以來的秒數或其他)
那麼,首先,我建議您使用「離線」處理來生成「圖形就緒」數據(對於大多數常見情況),而不是試圖查詢原始數據一經請求。
如果您使用的是MYSQL 5.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倍更快(差異將如果涉及複雜的連接,則要大得多)。
LIMIT 1當獲得一個唯一的行 SELECT * FROM用戶WHERE狀態= '阿拉巴馬' //錯誤 SELECT 1 FROM用戶WHERE狀態= '阿拉巴馬' LIMIT 1
索引搜索字段 索引不僅僅是主鍵或唯一鍵。如果表格中有任何要搜索的列,則應該幾乎總是對它們進行索引。
索引和用法連接的相同列類型 如果您的應用程序包含許多JOIN查詢,則需要確保通過兩個表索引您加入的列。這會影響MySQL在內部優化連接操作的方式。
不要按ORDER BY RAND() 如果你確實需要結果中的任意行,那麼有更好的方法。當然,它需要額外的代碼,但是您可以防止隨着數據增長而出現指數級惡化的瓶頸。問題是,在對數據進行排序並給你1行之前,MySQL必須對錶中的每一行執行RAND()操作(這需要處理能力)。
使用ENUM over VARCHAR ENUM類型的列非常快速而且緊湊。它們在內部存儲爲TINYINT,但它們可以包含並顯示字符串值。
使用NOT NULL如果您可以 除非您有一個非常具體的使用NULL值的原因,否則應始終將您的列設置爲NOT NULL。 「
」NULL列需要額外的空間來記錄它們的值是否爲NULL。對於MyISAM表,每個NULL列需要一位額外的,四捨五入到最近的字節。
將IP地址存儲爲UNSIGNED INT 在您的查詢中,您可以使用INET_ATON()將IP轉換爲整數,將INET_NTOA()反過來。 PHP中也有類似的函數,稱爲ip2long()和long2ip()。