2014-07-10 62 views
2

我有一位客戶要求我調整他的MySQL數據庫,以實現一些新功能並提高現有Web應用程序的性能。創建輔助表以提高大型MySQL表的性能?

最大的桌子(〜90 GB)擁有超過200M行,並且以定期間隔(每次訪問他擁有的任何一個網站時都會有一次)增長。由於連續的INSERT,從後端頁面執行的每個SELECT查詢需要一段時間才能完成,因爲每次都會重新生成索引。

我在我自己的服務器上從BTREE索引切換到HASH索引做了模擬。 SELECT和INSERT都沒有運行得更快。該表使用MyISAM作爲存儲引擎。只有INSERT和SELECT,沒有UPDATE或DELETE。

我想出了創建與每個INSERT一起更新的輔助表的想法,以加速來自後端的每個SELECT查詢。我知道這是不好的做法,但是,我確信統計頁面的表現會提高。

我不是一位數據庫性能專家,因爲您可能已經注意到了......是否有更好的方法呢?

順便說一下,從phpMyAdmin我看到,表上的大多數索引都有0的基數。在我的模擬中,這沒有發生。我不確定爲什麼會發生這種情況。

非常感謝。

第一次更新:我剛剛瞭解到,MyISAM引擎不支持散列索引。

第二次更新:好的。這是表格模式。

CREATE TABLE `visits` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`datetime` int(8) NOT NULL, 
`webmaster_id` char(18) NOT NULL, 
`country` char(2) NOT NULL, 
`connection` varchar(15) NOT NULL, 
`device` varchar(15) NOT NULL, 
`provider` varchar(100) NOT NULL, 
`ip_address` varchar(15) NOT NULL, 
`url` varchar(300) NOT NULL, 
`user_agent` varchar(300) NOT NULL, 
PRIMARY KEY (`id`), 
KEY `datetime` (`datetime`), 
KEY `webmaster_id` (`webmaster_id`), 
KEY `country` (`country`), 
KEY `connection` (`connection`), 
KEY `device` (`device`), 
KEY `provider` (`provider`) 
) ENGINE=InnoDB; 

因此,而不是像執行查詢select count(*) from visits where datetime=20140715 and device="ios",會不會是最好從select count from visits_stats where datetime=20140715 and device="ios"獲取呢?

如上所述,INSERT比SELECT更頻繁,但我的客戶希望提高用於檢索聚合數據的後端的性能。使用我的方法,每次訪問意味着一個INSERT和一個INSERT/UPDATE(或REPLACE),這會增加一個或多個計數器(我還沒有確定visitor_stats表的模式,上面的查詢只是一個例子)。

除此之外,我決定用某個外部表的合適ID替換一些字段。到目前爲止,數據存儲在像connection = cable,device = android等字符串中。我不確定這會如何影響性能。

再次感謝。

+1

你爲什麼不發佈查詢,表和索引的定義以及執行計劃,使這裏的人真的可以試着幫你嗎? –

回答

4

編輯:我之前說過不使用分區。但是比爾說得對,他所描述的方式會起作用。你唯一擔心的是如果你試圖在101個分區中進行選擇,那麼整個事情就會陷入癱瘓。如果你不打算這樣做,那麼分區將解決問題。首先修復你的索引。

您的主要問題是,MyISAM的是不是最好的引擎,也不是InnoDB的。 TokuDB將是你最好的選擇,但你必須在服務器上安裝它。

現在,你需要修剪你的索引。這是緩慢的主要原因。刪除不屬於普通SELECT語句的所有內容的索引。根據您的SELECT報表中的WHERE請求添加多列索引。

因此(除了您的主鍵),您希望datetime, device的索引僅作爲多列索引,根據您發佈的SELECT聲明。

如果更改爲TokuDB,插入將會快得多,如果您堅持使用MyISAM,那麼您可以通過使用INSERT DELAYED而不是INSERT來加速整個事情。與此唯一的問題是,刀片不會過日子,但是每當MySQL的決定沒有太多的負荷將增加。

另外,如果上述仍沒有幫助,您的最終選擇是使用兩個表。一個表,你SELECT從,另一個你INSERT到。一旦大概一天,你就可以將插入表複製到選擇表中。儘管這意味着您選擇的表格中的數據可能會長達24小時。

以外,你將不得不徹底改變表結構,爲此,我不能告訴你怎麼做,因爲這取決於您使用它到底是什麼,或者使用MySQL之外的東西這一點。不過,我上面的優化應該可以工作。

3

我會建議尋找分區。由於MySQL的限制,您必須將datetime添加到主鍵才能生效。主鍵或唯一鍵必須包含用於對錶進行分區的列。

同時將datetime上的索引轉換爲(datetime, device)的複合索引。這將是一個,其中包含您展示的查詢的索引,因此查詢可以單獨從索引獲取答案,而無需觸摸表格行。

CREATE TABLE `visits` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`datetime` int(8) NOT NULL, 
`webmaster_id` char(18) NOT NULL, 
`country` char(2) NOT NULL, 
`connection` varchar(15) NOT NULL, 
`device` varchar(15) NOT NULL, 
`provider` varchar(100) NOT NULL, 
`ip_address` varchar(15) NOT NULL, 
`url` varchar(300) NOT NULL, 
`user_agent` varchar(300) NOT NULL, 
PRIMARY KEY (`id`, `datetime`), -- compound primary key is necessary in this case 
KEY `datetime` (`datetime`,`device`), -- compound index for the SELECT 
KEY `webmaster_id` (`webmaster_id`), 
KEY `country` (`country`), 
KEY `connection` (`connection`), 
KEY `device` (`device`), 
KEY `provider` (`provider`) 
) ENGINE=InnoDB 
PARTITION BY HASH(datetime) PARTITIONS 101; 

所以,當你查詢select count(*) from visits where datetime=20140715 and device='ios',查詢只掃描一個分區,在表中的行約1%。然後在該分區內,使用索引進一步縮小範圍。

插入也應該改進,因爲它們正在更新更小的索引。

我使用一個素數做散列分區時,幫助分區保持更均勻充滿的情況下,插入的日期遵循規律。

將90GB表格轉換爲分區需要很長時間。您可以使用pt-online-schema-change來避免阻止您的應用程序。

,你甚至可以在MySQL 5.6賺更多的分區,如果你願意,在理論上可達1024在MySQL 5.5和8192。儘管有數千個分區,但您可能遇到不同的瓶頸,例如打開的文件數量。

P.S .: HASH索引不支持MyISAM或InnoDB。 HASH索引僅支持MEMORY和NDB存儲引擎。

2

您現在處在被稱爲大數據查詢/大數據處理的問題中。爲了處理大數據,很多解決方案可用,但不幸的是,它們都不容易實現。您始終需要一個團隊來構建大數據以滿足您的需求。我可能在這裏定義的一些解決方案如下。 1. Big Table Google使用這種技術創建了一個包含數千列的大型表(爲了儘量減少垂直記錄)。爲此,您必須分析數據,然後根據相似性進行分區,然後用適當的名稱標記這些相似性。現在您必須編寫查詢,這些查詢將首先通過某種算法進行分析,以檢查哪些列空間需要查詢。 沒有足夠簡單 2.分佈式數據庫橫跨多重機 的Hadoop文件系統是一種完全解決存儲和查詢大數據的問題創造了一個開源的Apache項目。在早期的時候,Space就是問題,系統足夠處理小數據,但現在空間不是問題。即使Small組織也有本地存儲的tera字節數據。但是這個TB級的數據不能一次性在一臺機器上處理。即使是一臺巨型機器也需要數天的時間來處理總體運營。這就是爲什麼hadoop在那裏。

如果你是個人,然後肯定你有麻煩了,你需要做這個痛苦的任務,爲您的資源。但是,您可以在不使用這些技術的情況下使用這些技術的精髓。
您可以自由嘗試這些技巧。只要研究處理大數據的文章。關係數據庫查詢是不是要去工作,你的情況