隨著互聯網的發展,各方面的數據越來越多,從最近兩年大數據越來越強的呼聲中就可見一斑。?
我們所做的項目雖算不上什么大項目,但是由于業務量的問題,數據也是相當的多。
數據一多,就很容易出現性能問題,而為了解決這個問題我們通常很容易想到集群、分片等。
但是在某些時候卻不一定必須要用集群、分片,也可以適當的使用數據分區。
什么是分區?
MySQL在未啟用分區功能時,數據庫的單個表內容是以單個文件的形式存放在文件系統上的。當啟用分區功能后,MySQL將按用戶指定的規則將單個表內容分割成幾個文件存放在文件系統上。分區分為水平分區和垂直分區,水平分區是將表的數據按行分割成不同的數據文件,而垂直分區則是將表的數據按列分割成不同的數據文件。分片要遵循完備性原則、可重構性原則與不相交原則。完備性代表所有數據必須映射到某個片段上。可重構性表示所有分片數據必須可以重新構成全局數據。不相交性表示不同分片上的數據沒有重復(除非你是特意做的冗余)。
大概是介于各方面的考慮,我們用的的表中就用到了range分區,數據庫是其他人在管理,但是因為用到了這個表,因此我便抽時間進行了簡單的學習。
據我的了解,要使用分區的話,必須要在創建表結構的時候就使用創建分區的語句,不能再后期更改。
例如我創建一個簡單的emp表,有id、name、age三個字段,然后根據id分區。正確的建表語句基本如下:
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 );
這里我是設置把整個表的數據分為三個區,id小于6的是一個區,區名稱p0;id介于6到11的屬于一個區,區名稱p1;然后所有id大于11的一個區,區名稱pmax。
整理一個語法,基本如下:
create?table?tablename( ?字段名?數據類型...) partition?by?range(分區依賴的字段名)( partition?分取名?values?less?than?(分區條件的值),...)
這里需要注意的是例子中的最后一行partition pmax values less than maxvalue,這一句中只有代表分區名的pmax是可以自己任意取得,剩下的單詞不能變,maxvalue代表上邊分區條件的最大值。
這樣的話能保證所有數據都能正常入庫,否則,假如沒有這一句的話,那么id大于等于11的數據便無法存入庫中,將會報錯。
表結構創建好以后,為了測試分區是否成功,我向表中插入了一些數據,語句如下:
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);
數據插入完成后,要驗證是否對應id的數據保存在了對應的分區,可以使用查詢分區的命令,如下:
SELECT?partition_name,partition_expression,partition_description,table_rows? FROM?information_schema.PARTITIONS? WHERE?table_schema?=?SCHEMA()?AND?table_name='emp'
查詢出的結果如圖:
可以看出partition_name是分區名,partition_expression是分區依賴的字段,partition_description可以理解成該分區的條件,table_rows表示該分區中現在有的數據量。
從上邊的數據中可以看出分區是成功的,但是如上分區雖然可以避免無法插入的問題,卻又出現了一個新的問題。
那就是最后一個pmax區的數據有可能非常的大,這樣一來,數據并不平均,不成比例,有可能使得查詢最后一個區的數據時依舊出現性能問題。所以,解決辦法大致有這樣三個:
一是在能控制分區字段數據的情況下,比如說這里的id,假如能明確的知道什么時候會是多大的值,那么就可以一開始的時候不要這個pmax,而是定期的增加分區。例如這里存在了p0、p1,那么可以在id即將到達11的時候增加p2、p3甚至更多。增加分區的語句示例如下:
ALTER?TABLE?emp?ADD?PARTITION(PARTITION?p2?VALUES?LESS?THAN?(16))
語法整理就是:
alter?table?tablename?add?partition(partition?分區名?values?lessthan?(分區條件))
上邊這個辦法可以解決數據不成比例的這個問題,只不過也同時存在隱患,那就是假如什么時候忘了增加后邊的分區,亦或者說是分區依賴的字段值超出了預料,那么就又可能導致數據無法入庫的問題。這樣一來又有兩種方法可以解決:
一是可以使用mysql的事務機制和存儲過程等,做一個mysql的定時任務,然后使數據庫系統自己在特定的時間增加分區。這樣一來基本上不會出現第一個方法所說的問題,只不過這種方法需要對mysql的事務和存儲過程也有一定的理解,操作起來有一定的難度。
我知道這個方法,暫時還沒有著手去實現,等后邊進一步了解事務和存儲過程后再給出相關的例子。
那么除開上邊這種定時任務的方法外,還有一個就是拆分分區的辦法,也就是還是使用之前有pmax分區的這個表結構,然后用拆分分區的語句來拆分pmax。示例如下:
ALTER?TABLE?emp?REORGANIZE?PARTITION?pmax?INTO( PARTITION?p2?VALUES?LESS?THAN?(16), PARTITION?pmax?VALUES?LESS?THAN?maxvalue )
然后我們再用查詢分區情況的語句查詢,便可以看到結果變成這樣:
很顯然,多出來了一個p2分區,拆分成功的同事不影響其他的功能。
那么這里分區拆分的語法整理如下:
alter?table?tablename?reorganize?partition?要拆分的分區名?into( partition?拆分后的分區名1?values?less?than?(條件), partition?拆分后的分區名2?values?lessthan?(條件),...)
好了,到這里基本上算是完成了,但是我們知道數據庫一般的操作都是增刪改查,我們這里已經有了增改查,卻自然也不能少了刪。
按理說正常的生產環境的數據庫應該是不能隨意刪除數據的,但是并不代表就不能刪,反而有的時候還必須要刪。
就比如我們項目中那個庫,由于數據量太大,即便是分區了也依舊會在大量數據的情況下變慢。而與此同時,我們是按時間分區的,實際使用過程中只需要用到幾天的數據,那么實際上很早以前的數據是可以刪除不要的,或者說備份以后刪除這個表的,這樣就需要用到刪除語句。
當然了,刪除可以用delete,但是這樣的話分區信息還在庫中,實際上也是沒必要要的,完全可以直接刪除分區,因為刪除分區的時候也同時會刪除這個區內的所有數據。
示例之前我們先查一下之前插入的所有數據,如圖:
這里示例刪除p0分區代碼如下:
ALTER?TABLE?emp??DROP?PARTITION?p0
然后先用查詢分區的代碼看一下,如圖
可以看到p0區不見了,在select * 一下,如圖:
可以看到id小于6的數據已經沒有了,數據刪除成功。
?以上就是mysql分區之range分區的詳細介紹的內容,更多相關內容請關注PHP中文網(www.php.cn)!