日常開發(fā)中我們經(jīng)常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過于龐大,導(dǎo)致數(shù)據(jù)庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯(lián)合查詢的情況,性能會更加糟糕。分表和表分區(qū)的目的就是減少數(shù)據(jù)庫的負(fù)擔(dān),提高數(shù)據(jù)庫的效率,通常點(diǎn)來講就是提高表的增刪改查效率。
分表是將一個大表按照一定的規(guī)則分解成多張具有獨(dú)立存儲空間的實(shí)體表,我們可以稱為子表,每個表都對應(yīng)三個文件,MYD數(shù)據(jù)文件,.MYI索引文件,.frm表結(jié)構(gòu)文件。這些子表可以分布在同一塊磁盤上,也可以在不同的機(jī)器上。app讀寫的時候根據(jù)事先定義好的規(guī)則得到對應(yīng)的子表名,然后去操作它。
分區(qū)和分表相似,都是按照規(guī)則分解表。不同在于分表將大表分解為若干個獨(dú)立的實(shí)體表,而分區(qū)是將數(shù)據(jù)分段劃分在多個位置存放,可以是同一塊磁盤也可以在不同的機(jī)器。分區(qū)后,表面上還是一張表,但數(shù)據(jù)散列到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分區(qū)的數(shù)據(jù)。 分區(qū)的主要目的是為了在特定的SQL操作中減少數(shù)據(jù)讀寫的總量以縮減響應(yīng)時間。
它并不是分表,但起到了和分表相同的作用。集群可分擔(dān)數(shù)據(jù)庫的操作次數(shù),將任務(wù)分擔(dān)到多臺數(shù)據(jù)庫上。集群可以讀寫分離,減少讀寫壓力。從而提升數(shù)據(jù)庫性能。
大表可以按照業(yè)務(wù)的規(guī)則來分解為多個子表。通常為以下幾種類型,也可自己定義規(guī)則。
Range(范圍)–這種模式允許將數(shù)據(jù)劃分不同范圍。例如可以將一個表通過年份劃分成若干個分區(qū)。Hash(哈希)–這中模式允許通過對表的一個或多個列的Hash Key進(jìn)行計(jì)算,最后通過這個Hash碼不同數(shù)值對應(yīng)的數(shù)據(jù)區(qū)域進(jìn)行分區(qū)。例如可以建立一個對表主鍵進(jìn)行分區(qū)的表。Key(鍵值)-上面Hash模式的一種延伸,這里的Hash Key是MySQL系統(tǒng)產(chǎn)生的。List(預(yù)定義列表)–這種模式允許系統(tǒng)通過預(yù)定義的列表的值來對數(shù)據(jù)進(jìn)行分割。Composite(復(fù)合模式) –以上模式的組合使用分表規(guī)則與分區(qū)規(guī)則一樣,在分區(qū)模塊詳細(xì)介紹。 下面以Range簡單介紹下如何分表(按照年份表)。
假設(shè)表結(jié)構(gòu)有4個字段:自增id,姓名,存款金額,存款日期 把存款日期作為規(guī)則分表,分別創(chuàng)建幾個表 2011年:account_2011 2012年:account_2012 …… 2015年:account_2015 app在讀寫的時候根據(jù)日期來查找對應(yīng)的表名,需要手動來判定。
var getTableName = function() { var data = { name: 'tom', money: 2800.00, date: '201410013059' }; var tablename = 'account_'; var year = parseInt(data.date.substring(0, 4)); if (year < 2012) { tablename += 2011; // account_2011 } else if (year < 2013) { tablename += 2012; // account_2012 } else if (year < 2014) { tablename += 2013; // account_2013 } else if (year < 2015) { tablename += 2014; // account_2014 } else { tablename += 2015; // account_2015 } return tablename;}merge分表,分為主表和子表,主表類似于一個殼子,邏輯上封裝了子表,實(shí)際上數(shù)據(jù)都是存儲在子表中的。
我們可以通過主表插入和查詢數(shù)據(jù),如果清楚分表規(guī)律,也可以直接操作子表。
子表2011年
CREATE TABLE `account_2011` (`id` int(11) NOT NULL AUTO_INCREMENT ,`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,`money` float NOT NULL ,`tradeDate` datetime NOT NULLPRIMARY KEY (`id`))ENGINE=MyISAMDEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ciAUTO_INCREMENT=2CHECKSUM=0ROW_FORMAT=DYNAMICDELAY_KEY_WRITE=0;子表2012年
CREATE TABLE `account_2012` (`id` int(11) NOT NULL AUTO_INCREMENT ,`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,`money` float NOT NULL ,`tradeDate` datetime NOT NULLPRIMARY KEY (`id`))ENGINE=MyISAMDEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ciAUTO_INCREMENT=2CHECKSUM=0ROW_FORMAT=DYNAMICDELAY_KEY_WRITE=0;主表,所有年
CREATE TABLE `account_all` (`id` int(11) NOT NULL AUTO_INCREMENT ,`name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ,`money` float NOT NULL ,`tradeDate` datetime NOT NULLPRIMARY KEY (`id`))ENGINE=MRG_MYISAMDEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ciUNION=(`account_2011`,`account_2012`)INSERT_METHOD=LASTROW_FORMAT=DYNAMIC;創(chuàng)建主表的時候有個INSERT_METHOD,指明插入方式,取值可以是:0 不允許插入;FIRST 插入到UNION中的第一個表; LAST 插入到UNION中的最后一個表。
通過主表查詢的時候,相當(dāng)于將所有子表合在一起查詢。這樣并不能體現(xiàn)分表的優(yōu)勢,建議還是查詢子表。
當(dāng)刪除了一個分區(qū),也同時刪除了該分區(qū)中所有的數(shù)據(jù)。
ALTER TABLE sale_data DROP PARTITION p201010;下面的SQL,將p201001 - p201009 合并為3個分區(qū)p2010Q1 - p2010Q3
ALTER TABLE sale_dataREORGANIZE PARTITION p201001,p201002,p201003,p201004,p201005,p201006,p201007,p201008,p201009 INTO(PARTITION p2010Q1 VALUES LESS THAN (201004),PARTITION p2010Q2 VALUES LESS THAN (201007),PARTITION p2010Q3 VALUES LESS THAN (201010));新聞熱點(diǎn)
疑難解答