隨著互聯(lián)網(wǎng)的發(fā)展,各方面的數(shù)據(jù)越來越多,從最近兩年大數(shù)據(jù)越來越強(qiáng)的呼聲中就可見一斑。?
我們所做的項(xiàng)目雖算不上什么大項(xiàng)目,但是由于業(yè)務(wù)量的問題,數(shù)據(jù)也是相當(dāng)?shù)亩唷?
數(shù)據(jù)一多,就很容易出現(xiàn)性能問題,而為了解決這個問題我們通常很容易想到集群、分片等。
但是在某些時候卻不一定必須要用集群、分片,也可以適當(dāng)?shù)氖褂脭?shù)據(jù)分區(qū)。
什么是分區(qū)?
MySQL在未啟用分區(qū)功能時,數(shù)據(jù)庫的單個表內(nèi)容是以單個文件的形式存放在文件系統(tǒng)上的。當(dāng)啟用分區(qū)功能后,MySQL將按用戶指定的規(guī)則將單個表內(nèi)容分割成幾個文件存放在文件系統(tǒng)上。分區(qū)分為水平分區(qū)和垂直分區(qū),水平分區(qū)是將表的數(shù)據(jù)按行分割成不同的數(shù)據(jù)文件,而垂直分區(qū)則是將表的數(shù)據(jù)按列分割成不同的數(shù)據(jù)文件。分片要遵循完備性原則、可重構(gòu)性原則與不相交原則。完備性代表所有數(shù)據(jù)必須映射到某個片段上。可重構(gòu)性表示所有分片數(shù)據(jù)必須可以重新構(gòu)成全局?jǐn)?shù)據(jù)。不相交性表示不同分片上的數(shù)據(jù)沒有重復(fù)(除非你是特意做的冗余)。
大概是介于各方面的考慮,我們用的的表中就用到了range分區(qū),數(shù)據(jù)庫是其他人在管理,但是因?yàn)橛玫搅诉@個表,因此我便抽時間進(jìn)行了簡單的學(xué)習(xí)。
據(jù)我的了解,要使用分區(qū)的話,必須要在創(chuàng)建表結(jié)構(gòu)的時候就使用創(chuàng)建分區(qū)的語句,不能再后期更改。
例如我創(chuàng)建一個簡單的emp表,有id、name、age三個字段,然后根據(jù)id分區(qū)。正確的建表語句基本如下:
CREATE?TABLE?emp( id?INT?NOT?NULL, NAME?VARCHAR(20), age?INT) PARTITION?BY?RANGE(ID)( PARTITION?p0?VALUES?LESS?THAN?(6), PARTITION?p1?VALUES?LESS?THAN?(11), PARTITION?pmax?VALUES?LESS?THAN?maxvalue );
這里我是設(shè)置把整個表的數(shù)據(jù)分為三個區(qū),id小于6的是一個區(qū),區(qū)名稱p0;id介于6到11的屬于一個區(qū),區(qū)名稱p1;然后所有id大于11的一個區(qū),區(qū)名稱pmax。
整理一個語法,基本如下:
create?table?tablename( ?字段名?數(shù)據(jù)類型...) partition?by?range(分區(qū)依賴的字段名)( partition?分取名?values?less?than?(分區(qū)條件的值),...)
這里需要注意的是例子中的最后一行partition pmax values less than maxvalue,這一句中只有代表分區(qū)名的pmax是可以自己任意取得,剩下的單詞不能變,maxvalue代表上邊分區(qū)條件的最大值。
這樣的話能保證所有數(shù)據(jù)都能正常入庫,否則,假如沒有這一句的話,那么id大于等于11的數(shù)據(jù)便無法存入庫中,將會報錯。
表結(jié)構(gòu)創(chuàng)建好以后,為了測試分區(qū)是否成功,我向表中插入了一些數(shù)據(jù),語句如下:
INSERT?INTO?emp?VALUES(1,'test1',22);INSERT?INTO?emp?VALUES(2,'test2',25);INSERT?INTO?emp?VALUES(3,'test3',27); INSERT?INTO?emp?VALUES(4,'test4',20);INSERT?INTO?emp?VALUES(5,'test5',22);INSERT?INTO?emp?VALUES(6,'test6',25); INSERT?INTO?emp?VALUES(7,'test7',27);INSERT?INTO?emp?VALUES(8,'test8',20);INSERT?INTO?emp?VALUES(9,'test9',22); INSERT?INTO?emp?VALUES(10,'test10',25);INSERT?INTO?emp?VALUES(11,'test11',27);INSERT?INTO?emp?VALUES(12,'test12',20); INSERT?INTO?emp?VALUES(13,'test13',22);INSERT?INTO?emp?VALUES(14,'test14',25);INSERT?INTO?emp?VALUES(15,'test15',27); INSERT?INTO?emp?VALUES(16,'test16',20);INSERT?INTO?emp?VALUES(17,'test17',30);INSERT?INTO?emp?VALUES(18,'test18',40); INSERT?INTO?emp?VALUES(19,'test19',20);
數(shù)據(jù)插入完成后,要驗(yàn)證是否對應(yīng)id的數(shù)據(jù)保存在了對應(yīng)的分區(qū),可以使用查詢分區(qū)的命令,如下:
SELECT?partition_name,partition_expression,partition_description,table_rows? FROM?information_schema.PARTITIONS? WHERE?table_schema?=?SCHEMA()?AND?table_name='emp'
查詢出的結(jié)果如圖:
可以看出partition_name是分區(qū)名,partition_expression是分區(qū)依賴的字段,partition_description可以理解成該分區(qū)的條件,table_rows表示該分區(qū)中現(xiàn)在有的數(shù)據(jù)量。
從上邊的數(shù)據(jù)中可以看出分區(qū)是成功的,但是如上分區(qū)雖然可以避免無法插入的問題,卻又出現(xiàn)了一個新的問題。
那就是最后一個pmax區(qū)的數(shù)據(jù)有可能非常的大,這樣一來,數(shù)據(jù)并不平均,不成比例,有可能使得查詢最后一個區(qū)的數(shù)據(jù)時依舊出現(xiàn)性能問題。所以,解決辦法大致有這樣三個:
一是在能控制分區(qū)字段數(shù)據(jù)的情況下,比如說這里的id,假如能明確的知道什么時候會是多大的值,那么就可以一開始的時候不要這個pmax,而是定期的增加分區(qū)。例如這里存在了p0、p1,那么可以在id即將到達(dá)11的時候增加p2、p3甚至更多。增加分區(qū)的語句示例如下:
ALTER?TABLE?emp?ADD?PARTITION(PARTITION?p2?VALUES?LESS?THAN?(16))
語法整理就是:
alter?table?tablename?add?partition(partition?分區(qū)名?values?lessthan?(分區(qū)條件))
上邊這個辦法可以解決數(shù)據(jù)不成比例的這個問題,只不過也同時存在隱患,那就是假如什么時候忘了增加后邊的分區(qū),亦或者說是分區(qū)依賴的字段值超出了預(yù)料,那么就又可能導(dǎo)致數(shù)據(jù)無法入庫的問題。這樣一來又有兩種方法可以解決:
一是可以使用mysql的事務(wù)機(jī)制和存儲過程等,做一個mysql的定時任務(wù),然后使數(shù)據(jù)庫系統(tǒng)自己在特定的時間增加分區(qū)。這樣一來基本上不會出現(xiàn)第一個方法所說的問題,只不過這種方法需要對mysql的事務(wù)和存儲過程也有一定的理解,操作起來有一定的難度。
我知道這個方法,暫時還沒有著手去實(shí)現(xiàn),等后邊進(jìn)一步了解事務(wù)和存儲過程后再給出相關(guān)的例子。
那么除開上邊這種定時任務(wù)的方法外,還有一個就是拆分分區(qū)的辦法,也就是還是使用之前有pmax分區(qū)的這個表結(jié)構(gòu),然后用拆分分區(qū)的語句來拆分pmax。示例如下:
ALTER?TABLE?emp?REORGANIZE?PARTITION?pmax?INTO( PARTITION?p2?VALUES?LESS?THAN?(16), PARTITION?pmax?VALUES?LESS?THAN?maxvalue )
然后我們再用查詢分區(qū)情況的語句查詢,便可以看到結(jié)果變成這樣:
很顯然,多出來了一個p2分區(qū),拆分成功的同事不影響其他的功能。
那么這里分區(qū)拆分的語法整理如下:
alter?table?tablename?reorganize?partition?要拆分的分區(qū)名?into( partition?拆分后的分區(qū)名1?values?less?than?(條件), partition?拆分后的分區(qū)名2?values?lessthan?(條件),...)
好了,到這里基本上算是完成了,但是我們知道數(shù)據(jù)庫一般的操作都是增刪改查,我們這里已經(jīng)有了增改查,卻自然也不能少了刪。
按理說正常的生產(chǎn)環(huán)境的數(shù)據(jù)庫應(yīng)該是不能隨意刪除數(shù)據(jù)的,但是并不代表就不能刪,反而有的時候還必須要刪。
就比如我們項(xiàng)目中那個庫,由于數(shù)據(jù)量太大,即便是分區(qū)了也依舊會在大量數(shù)據(jù)的情況下變慢。而與此同時,我們是按時間分區(qū)的,實(shí)際使用過程中只需要用到幾天的數(shù)據(jù),那么實(shí)際上很早以前的數(shù)據(jù)是可以刪除不要的,或者說備份以后刪除這個表的,這樣就需要用到刪除語句。
當(dāng)然了,刪除可以用delete,但是這樣的話分區(qū)信息還在庫中,實(shí)際上也是沒必要要的,完全可以直接刪除分區(qū),因?yàn)閯h除分區(qū)的時候也同時會刪除這個區(qū)內(nèi)的所有數(shù)據(jù)。
示例之前我們先查一下之前插入的所有數(shù)據(jù),如圖:
這里示例刪除p0分區(qū)代碼如下:
ALTER?TABLE?emp??DROP?PARTITION?p0
然后先用查詢分區(qū)的代碼看一下,如圖
可以看到p0區(qū)不見了,在select * 一下,如圖:
可以看到id小于6的數(shù)據(jù)已經(jīng)沒有了,數(shù)據(jù)刪除成功。
?以上就是mysql分區(qū)之range分區(qū)的詳細(xì)介紹的內(nèi)容,更多相關(guān)內(nèi)容請關(guān)注PHP中文網(wǎng)(www.php.cn)!