轉載於:https://www.2cto.com/database/201411/348519.html
如果有一張大表,表中的數據有幾百萬、幾千萬甚至上億,要實現實時查詢,查詢的結果要在十秒鍾之內出來,怎么辦?如何做優化?
本人現在做的項目中,有個表的數據超過1千萬行,超過3G的數據。現在需要對表中的數據進行查詢統計,之前由於沒做優化,導致此表的查詢效率非常低下,讓使用者非常苦惱,於是本人參與了此表的優化。
舉個類似的例子,比如表中的結構如下,現在要統計某一天出生的人口數,或者統計某一城市的人口數,或者某一城市某一天出生的人口數。
CREATE TABLE `population` ( `population_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '人口表', `name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '姓名', `city` varchar(32) COLLATE utf8_bin DEFAULT NULL COMMENT '城市', `birthday` date DEFAULT NULL COMMENT '出生日期', PRIMARY KEY (`population_id`) ) 查詢某一城市某一天出生的人口數 SELECT COUNT(*) FROM population WHERE city='廣州' AND birthday = '2014-11-02' 查詢某一城市的人口數 SELECT COUNT(*) FROM population WHERE city='廣州' 查詢某一天出生的人口數 SELECT COUNT(*) FROM population WHERE birthday = '2014-11-02'
提出了兩個優化方案,
(1).優化索引
通過添加索引后,查詢的效率得到極大的提升,常用查詢的查詢時間從原來的幾十秒下降到幾秒。
建立以下兩個單列索引
ALTER TABLE `population`
ADD INDEX `fk_city` (`city`),
ADD INDEX `fk_birthday` (`birthday`);
也可以建立以下兩個組合索引
ALTER TABLE `population`
ADD INDEX `fk_index1` (`city`, `birthday`),
ADD INDEX `fk_index2` (`birthday`, `city`);
(2).使用中間表
雖然索引優化可以將查詢時間大大減少,但如果數據量達到一定量時,有些情況下索引到的數據達到幾百萬時,查詢仍然會很慢,因此索引優化無法從根本上解決問題。現在表中的數據量越來越大,平均每個月要增加一兩百萬的數據,索引的優化方法只是暫時的,只能解決小數據量的查詢問題,隨着數據量的快速增長,索引帶來的性能優化很容易達到極限,要尋找其他的解決方案。
我們根據業務需求的特點,創建中間表population_statistics,將表population中的統計數據存放到中間表population_statistics中,查詢時直接從中間表population_statistics中查詢。注意,在對表population進行增、刪、改時,必須同時更新population_statistics中的數據,否則會出現數據不一致的錯誤!
CREATE TABLE `population_statistics` ( `population_statistics_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '人口統計表ID', `city` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '城市', `birthday` int(32) DEFAULT NULL COMMENT '出生日期', `total_count` int(32) DEFAULT NULL COMMENT '人口數量', PRIMARY KEY (`population_statistics_id`), KEY `fk_city` (`city`), KEY `fk_birthday` (`birthday`) ) 查詢某一城市某一天出生的人口數 SELECT total_count FROM population_statistics WHERE city='廣州' AND birthday = '2014-11-02'; 查詢某一城市的人口數 SELECT COUNT(total_count) FROM population_statistics WHERE city='廣州'; 查詢某一天出生的人口數 SELECT COUNT(total_count) FROM population_statistics WHERE birthday = '2014-11-02';
某個城市某一天的人口在表population中可能有幾千甚至萬的數據,而在統計表population_statistics中最多只有一條數據,也就是說統計表population_statistics中的數據量只有人口表population的幾千分之一,再加上索引的優化,查詢的速度會極大提高。
下面總結一下常用的大數據表優化方案.
1. 索引優化
通過建立合理高效的索引,提高查詢的速度.
建議閱讀本人寫的一篇關於索引的博客
http://blog.csdn.net/brushli/article/details/39677387
2. SQL優化
組織優化SQL語句,使查詢效率達到最優,在很多情況下要考慮索引的作用.
建議閱讀考本人寫的一篇關於索引的博客
http://blog.csdn.net/brushli/article/details/39677387
3. 水平拆表
如果表中的數據呈現出某一類特性,比如呈現時間特性,那么可以根據時間段將表拆分成多個。
比如按年划分、按季度划分、按月划分等等,查詢時按時間段進行拆分查詢,再把查詢結果進行合並;
比如按地區將表拆分,不同地區的數據放在不同的表里面,然后對查詢進行分拆,對查詢結果進行合並。
4. 垂直拆表
將表按字段拆分成多個表,常用的字段放在一個表,不常用的字段或大字段放在另外一個表。由於數據庫每次查詢都是以塊為單位,而每塊的容量是有限的,通常是十幾K或幾十K,將表按字段拆分后,單次IO所能檢索到的行數通常會提高很多,查詢效率就能提高上去。
比如有成員表,結構如下:
CREATE TABLE `member` ( `member_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '成員表ID', `name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '成員姓名', `age` int(32) DEFAULT NULL COMMENT '成員年齡', `introduction` text COLLATE utf8_bin COMMENT '成員介紹', PRIMARY KEY (`member_id`) )
introduction是大字段,保存成員的介紹,這個大字段會嚴重影響查詢效率,可以將它獨立出來,單獨形成一個表。
CREATE TABLE `member` ( `member_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '成員表ID', `name` varchar(128) COLLATE utf8_bin DEFAULT NULL COMMENT '成員姓名', `age` int(32) DEFAULT NULL COMMENT '成員年齡', PRIMARY KEY (`member_id`) ) CREATE TABLE `member_introduction` ( `member_introduction_id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '成員介紹表ID', `member_id` bigint(64) DEFAULT NULL COMMENT '成員ID', `introduction` text COLLATE utf8_bin COMMENT '成員介紹', PRIMARY KEY (`member_introduction_id`), KEY `fk_member_id` (`member_id`), CONSTRAINT `fk_member_id` FOREIGN KEY (`member_id`) REFERENCES `member` (`member_id`) )
5. 建立中間表,以空間換時間
在有些情況下,是可以通過建立中間表來加快查詢速度的,詳情可看文章開頭的例子。
6. 用內存緩存數據,以空間換時間
將常用而且不常修改的數據加載到內存中,直接從內存查詢則可。
可以使用熱門的緩存技術,如Memcache、Redis、Ehcache等。
7. 使用其他輔助技術
Solr:一種基於Lucene的JAVA搜索引擎技術