我們的業(yè)務(wù)只存近一段時間的數(shù)據(jù),因此有大量表需要清理 歷史 數(shù)據(jù),目前使用的delete清理數(shù)據(jù),存在以下問題。為避免同時支持大量delete,我們的清理任務(wù)只在低峰期串行執(zhí)行,導(dǎo)致任務(wù)過多時需要排隊,甚至失敗的情況;數(shù)據(jù)清理使用delete語句,表數(shù)據(jù)量較大時,對數(shù)據(jù)庫造成很大壓力;即使我們刪除了舊數(shù)據(jù),已刪除的數(shù)據(jù)仍占據(jù)存儲空間,底層數(shù)據(jù)文件并沒有立刻變小,以至于形成數(shù)據(jù)空洞。
創(chuàng)新互聯(lián)公司是專業(yè)的竹溪網(wǎng)站建設(shè)公司,竹溪接單;提供成都做網(wǎng)站、網(wǎng)站設(shè)計,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行竹溪網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
查看MySQL官方文檔時,發(fā)現(xiàn)了分區(qū)表,因此基于官方文檔總結(jié)一下。
MySQL邏輯上為一個表,物理上存儲在多個文件中,這是 MySQL 支持的功能(5.1 開始), 8.0 版本只 InnoDB 和 NDB 支持分區(qū)表。
優(yōu)點(diǎn):
缺點(diǎn):
根據(jù)分區(qū)表鍵值的范圍把數(shù)據(jù)存儲到表的不同分區(qū)中,適用于以時間或日期作為分區(qū)類型,方便數(shù)據(jù)清理。
小提示:
1.當(dāng)插入數(shù)據(jù)分區(qū)不存在時會報錯:Table has no partition for value xxx;
2.Range類型分區(qū)字段必須是數(shù)值,時間類型可用函數(shù)轉(zhuǎn)換為數(shù)值;
3.分區(qū)字段列值可以為null,所有為null的數(shù)據(jù)將存在最小的分區(qū)中;
按分區(qū)鍵取值的列表進(jìn)行分區(qū),每一行數(shù)據(jù)須找到對應(yīng)的分區(qū)列表,否則數(shù)據(jù)插入失敗
小提示:
根據(jù)指定分區(qū)表達(dá)式的整數(shù)值以及分區(qū)數(shù)進(jìn)行數(shù)據(jù)劃分(mod函數(shù))
小提示:
按鍵分區(qū)類似于按哈希分區(qū),只是哈希分區(qū)使用用戶定義的表達(dá)式,用于鍵分區(qū)的哈希函數(shù)由 MySQL 服務(wù)器提供。NDB 集群為此使用 MD5() ; 對于使用其他存儲引擎的表,服務(wù)器使用自己的內(nèi)部哈希函數(shù)。
小提示:
子分區(qū)(subpartitioning)也稱為復(fù)合分區(qū)(composite partitioning) ,是已分區(qū)表中每個分區(qū)的進(jìn)一步劃分
小提示:
小提示:
??表分區(qū)是將?個表的數(shù)據(jù)按照?定的規(guī)則?平劃分為不同的邏輯塊,并分別進(jìn)?物理存儲,這個規(guī)則就叫做分區(qū)函數(shù),可以有不同的分區(qū)規(guī)則。5.7可以通過show plugins語句查看當(dāng)前MySQL是否?持表分區(qū)功能。
??但當(dāng)表中含有主鍵或唯?鍵時,則每個被?作 分區(qū)函數(shù)的字段必須是表中唯?鍵和主鍵的全部或?部分 ,否則就?法創(chuàng)建分區(qū)表。?如下?的表由于唯?鍵和主鍵沒有相同的字段,所以?法創(chuàng)建表分區(qū)
上述例?中刪除唯?鍵,確保主鍵中的字段包含分區(qū)函數(shù)中的所有字段,創(chuàng)建成功
或者將主鍵擴(kuò)展為包含ref字段
表分區(qū)的主要優(yōu)勢在于:
??可以允許在?個表?存儲更多的數(shù)據(jù),突破磁盤限制或者?件系統(tǒng)限制
??對于從表?將過期或歷史的數(shù)據(jù)移除在表分區(qū)很容易實現(xiàn),只要將對應(yīng)的分區(qū)移除即可
??對某些查詢和修改語句來說,可以 ?動 將數(shù)據(jù)范圍縮?到?個或?個表分區(qū)上,優(yōu)化語句執(zhí)?效率。?且可以通過 顯示指定表分區(qū) 來執(zhí)?語句,?如 SELECT * FROM t PARTITION (p0,p1) WHERE c 5
表分區(qū)類型分為:
范圍表分區(qū),按照?定的范圍值來確定每個分區(qū)包含的數(shù)據(jù),分區(qū)函數(shù)使?的字段必須只能是 整數(shù)類型,分區(qū)的定義范圍必須是連續(xù)的,且不能有重疊部分,通過使?VALUES LESS THAN來定義分區(qū)范圍,表分區(qū)的范圍定義是從?到?定義的
?如:
??Store_id6的數(shù)據(jù)被放在p0分區(qū)?,6=store_id10之間的數(shù)據(jù)被放在p1分區(qū)?,以此類推,當(dāng)新插?的數(shù)據(jù)為(72, ‘Mitchell’, ‘Wilson’, ‘1998-06-25’, NULL, 13) 時,則新數(shù)據(jù)被插?到p2分區(qū)?,但當(dāng)插?的數(shù)據(jù)的store_id為21時,由于沒有分區(qū)去容納此數(shù)據(jù),所以會報錯,我們需要修改?下表的定義
報錯:
修改表的定義:
?? MAXVALUE關(guān)鍵詞的作?是表示可能的最?值,所以任何store_id=16的數(shù)據(jù)都會被寫?到p3分區(qū)?。分區(qū)函數(shù)中也可以使?表達(dá)式 ,?如:
?? 對timestamp字段類型可以使?的表達(dá)式?前僅有unix_timestamp ,其他的表達(dá)式都不允許
列表表分區(qū),按照?個?個確定的值來確定每個分區(qū)包含的數(shù)據(jù),通過PARTITION BY LIST(expr)分區(qū)函數(shù)表達(dá)式必須返回整數(shù),取值范圍通過VALUES IN (value_list)定義
對List表分區(qū)來說,沒有MAXVALUE特殊值,所有的可能取值都需要再VALUES IN中包含,如果有未定義的取值則會報錯
同樣,當(dāng)有主鍵或者唯?鍵存在的情況下,分區(qū)函數(shù)字段需要包含在主鍵或唯?鍵中
對range和list表分區(qū)來說,分區(qū)函數(shù)可以包含多個字段,分區(qū)多字段函數(shù)(column partition) 所涉及的字段類型可以包括:
范圍多字段分區(qū)函數(shù)與普通的范圍分區(qū)函數(shù)的區(qū)別在于:
a) 字段類型多樣化
b) 范圍多字段分區(qū)函數(shù) 不?持表達(dá)式,只能?字段名
c) 范圍多字段分區(qū)函數(shù)?持?個或多個字段
再?如創(chuàng)建如下的表分區(qū):
對多列對?來說:
當(dāng)然只要保證取值范圍是增?的,表分區(qū)就能創(chuàng)建成功,?如:
但如果 取值范圍不是增?的,就會返回錯誤 :
對其他數(shù)據(jù)類型的?持:
list列表多字段表分區(qū),例如:你有一個在12個城市客戶的業(yè)務(wù), 為了銷售和市場的目的, 你的組織每3個城市劃分為一個區(qū)域針對LIST COLUMNS分區(qū), 你可以基于城市的名稱創(chuàng)建一個客戶數(shù)據(jù)表并聲明4個分區(qū)當(dāng)你的客戶在對應(yīng)的這個區(qū)域:
使用日期分區(qū)
但是這種情況在日期增長到非常大的時候是很復(fù)雜的, 所以這種還是使用RANGE 分區(qū)方式比較好
??按照?個?定義的函數(shù)返回值來確定每個分區(qū)包含的數(shù)據(jù),這個 ?定義函數(shù)也可以僅僅是?個字段名字
??通過PARTITION BY HASH (expr)?句來表達(dá)哈希表分區(qū),其中的 expr表達(dá)式必須返回?個整數(shù),基于分區(qū)個數(shù)的取模(%)運(yùn)算。根據(jù)余數(shù)插?到指定的分區(qū)
??對哈希表分區(qū)來說只需要定義分區(qū)的個數(shù),其他的事情由內(nèi)部完成
如果沒有寫明PARTITIONS字段,則默認(rèn)為1,表達(dá)式可以是整數(shù)類型字段,也可以是?個函數(shù),?如
?如: CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY HASH( YEAR(col3) ) PARTITIONS 4;
如果插??條數(shù)據(jù)對應(yīng)的col3為‘2005-09-15’時,則插?數(shù)據(jù)的分區(qū)計算?法為:
??與哈希表分區(qū)類似,只不過哈希表分區(qū)依賴于?定義的函數(shù),?key表分區(qū)的哈希算法是依賴MySQL本身, CREATE TABLE ... PARTITION BY KEY () 創(chuàng)建key表分區(qū), 括號??可以包含0個或者多個字段,所引?的字段必須是主鍵或者主鍵的?部分 ,如果括號??沒有字段,則代表使?主鍵
如果表中沒有主鍵但有唯?鍵,則使?唯?鍵,但 唯?鍵字段必須定義為not null ,否則報錯
所引?的字段未必必須是整數(shù)類型,其他的類型也可以使?,?如:
?表分區(qū),是在表分區(qū)的基礎(chǔ)上再創(chuàng)建表分區(qū)的概念, 每個表分區(qū)下的?表分區(qū)個數(shù)必須?致 ,?如:
ts表擁有三個范圍分區(qū),同時每個分區(qū)都各?有兩個?分區(qū),所以總共有6個分區(qū)
?表分區(qū)必須是范圍/列表分區(qū)+哈希/key?表分區(qū)的組合
?表分區(qū)也可以顯示的指定?表分區(qū)的名字,?如:
不同的表分區(qū)對NULL值的處理?式不同
對范圍表分區(qū)來說,如果插?的是NULL值,則將數(shù)據(jù)放到最?的分區(qū)表?
對list表分區(qū)來說,?持NULL值的唯?情況就是某個分區(qū)的允許值中包含NULL
對哈希表分區(qū)和Key表分區(qū)來說,NULL值會被當(dāng)成0值對待
通過alter table命令可以執(zhí)?增加,刪除,重新定義,合并或者拆分表分區(qū)的管理動作
對范圍表分區(qū)和列表表分區(qū)來說,刪除?個表分區(qū)命令如下:
刪除表分區(qū)的動作不光會把分區(qū)刪掉,也會把表分區(qū)?原來的數(shù)據(jù)給刪除掉
在原分區(qū)上增加?個表分區(qū)可以通過alter table … add partition語句來完成
但對范圍表分區(qū)來說,增加的表分區(qū)必須在尾部增加,在頭部或者在中間增加都會失?。?/p>
為解決這個問題,可以使? REORGANIZE 命令:
對列表表分區(qū)來說,只要新增加的分區(qū)對應(yīng)的值在之前的表分區(qū)中沒有出現(xiàn)過,就可以通過alter table… add partition來增加
當(dāng)然, 也可以通過REORGANIZE命令將之前的多個分區(qū)合并成?個或?個分區(qū),但要保持分區(qū)值?致:
更復(fù)雜的?如將多個分區(qū)重組成多個分區(qū):
一、查詢mysql表是否為分區(qū)表:可以查看表具有哪幾個分區(qū)、分區(qū)的方法、分區(qū)中數(shù)據(jù)的記錄數(shù)等信息
SELECT PARTITION_NAME,PARTITION_METHOD,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS,SUBPARTITION_NAME,SUBPARTITION_METHOD,SUBPARTITION_EXPRESSION
FROM information_schema.PARTITIONS WHERE TABLE_SCHEMA=SCHEMA() AND TABLE_NAME='xw_coobill_order';
二、查詢表有多少個分區(qū)
SELECT TABLE_NAME, COUNT(*) AS CNT
FROM information_schema.PARTITIONS WHERE PARTITION_NAME IS NOT NULL
GROUP BY TABLE_NAME ORDER BY CNT DESC LIMIT 50;
三、分析執(zhí)行語句
explain partitions select * from range_datetime where hiredate = '20151207124503' and hiredate='20151210111230';
四、分區(qū)管理
常規(guī)HASH和線性HASH的增加收縮分區(qū)的原理是一樣的。增加和收縮分區(qū)后原來的數(shù)據(jù)會根據(jù)現(xiàn)有的分區(qū)數(shù)量重新分布。HASH分區(qū)不能刪除分區(qū),所以不能使用DROP PARTITION操作進(jìn)行分區(qū)刪除操作;
只能通過ALTER TABLE ... COALESCE PARTITION num來合并分區(qū),這里的num是減去的分區(qū)數(shù)量;
可以通過ALTER TABLE ... ADD PARTITION PARTITIONS num來增加分區(qū),這里是null是在原先基礎(chǔ)上再增加的分區(qū)數(shù)量。
CREATE TABLE employees ( id INT NOT NULL, /SPAN/p fname VARCHAR(30), /SPAN/p lname VARCHAR(30), /SPAN/p hired DATE NOT NULL DEFAULT '1970-01-01', /SPAN/pseparated DATE NOT NULL DEFAULT '9999-12-31', /SPAN/p job_code INT NOT NULL, /SPAN/pstore_id INT NOT NULL /SPAN/p) PARTITION BY RANGE (store_id) ( /SPAN/p PARTITION p0 VALUES LESS THAN (6), /SPAN/p PARTITION p1 VALUES LESS THAN (11), /SPAN/p PARTITION p2 VALUES LESS THAN (16), /SPAN/pPARTITION p3 VALUES LESS THAN MAXVALUE /SPAN/p); 這就是根據(jù)store_id的值來進(jìn)行分區(qū)你也可以參看相關(guān)資料詳細(xì)了解:
對底層表的封裝,意味著索引也是按照分區(qū)的子表定義的,而沒有全局索引。(所以即使有唯一性索引,在不同子表中可能會有重復(fù)數(shù)據(jù))
單表數(shù)據(jù)量超大時索引失效
將單表分區(qū)成數(shù)個區(qū)域,通過分區(qū)函數(shù),可以快速地定位到數(shù)據(jù)的區(qū)域。而且相比于索引,分區(qū)不需要額外的數(shù)據(jù)結(jié)構(gòu)記錄每個分區(qū)的數(shù)據(jù),代價更低。只需要一個簡單的表達(dá)式就可以指向正確的分區(qū)
可以只是用簡單的分區(qū)方式存放表,不要任何索引,只要將查詢定位到需要的大致數(shù)據(jù)位置,通過where條件,將需要的數(shù)據(jù)限制在少數(shù)分區(qū)中,則效率是很高的。WARNNING:查詢需要掃描的分區(qū)個數(shù)限制在一個很小的數(shù)量。
如果數(shù)據(jù)有明顯的“熱點(diǎn)”,可以將熱點(diǎn)數(shù)據(jù)單獨(dú)放在一個分區(qū),讓這個分區(qū)的數(shù)據(jù)能夠有機(jī)會都緩存在內(nèi)存中。
如果分區(qū)表達(dá)式的值可以是NULL:第一個分區(qū)會使一個特殊分區(qū)。以partition by range year(order_date)為例,所有在order_date列為NULL或者非法值的數(shù)據(jù)都會被放到第一個分區(qū)。那么所有的查詢在定位分區(qū)后都會增加掃描第一個分區(qū)。而且如果第一個分區(qū)很大的時候,查詢的成本會被這個“拖油瓶”分區(qū)無情的增加。
創(chuàng)建一個無用的第一分區(qū)可以解決這個問題,partition p_nulls values less than (0);
對于分區(qū)列和索引列不匹配的查詢,雖然查詢能夠使用索引,但是無法通過分區(qū)定位到目標(biāo)數(shù)據(jù)的分區(qū)(也就是數(shù)據(jù)分布相對更加分散),需要遍歷每個分區(qū)內(nèi)的索引,除非查詢中的條件同時也包含分區(qū)條件。所以期望分區(qū)條件范圍被熱門查詢索引所包含。
對于 范圍分區(qū) 技術(shù),需要適當(dāng)限制分區(qū)的數(shù)量,否則對于大量數(shù)據(jù)批量導(dǎo)入的場景,選擇分區(qū)的成本過高。對于大多數(shù)系統(tǒng),100個左右的分區(qū)是沒有問題的。
以下是創(chuàng)建一張測試表TEST并且按照時間CREATE_TIME創(chuàng)建RANGE分區(qū),并使用ID創(chuàng)建hash分區(qū),組成復(fù)合分區(qū)。
CREATE TABLE TEST (
CREATE_TIME DATETIME DEFAULT NULL, ID BIGINT(15) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8
PARTITION BY RANGE(TO_DAYS(CREATE_TIME)) PARTITIONS 7 SUBPARTITION BY HASH(ID) SUBPARTITIONS 16
(PARTITION P1710 VALUES LESS THAN (TO_DAYS ('2017-10-01'))
(SUBPARTITION P1710sp0 ,SUBPARTITION P1710sp1 ,
SUBPARTITION P1710sp2 ,SUBPARTITION P1710sp3 ,
SUBPARTITION P1710sp4 ,SUBPARTITION P1710sp5 ,
SUBPARTITION P1710sp6 ,SUBPARTITION P1710sp7 ,
SUBPARTITION P1710sp8 ,SUBPARTITION P1710sp9 ,
SUBPARTITION P1710sp10 ,SUBPARTITION P1710sp11 ,
SUBPARTITION P1710sp12 ,SUBPARTITION P1710sp13 ,
SUBPARTITION P1710sp14 ,SUBPARTITION P1710sp15 ),
PARTITION P1711 VALUES LESS THAN (TO_DAYS ('2017-11-01'))
(SUBPARTITION P1711sp0 ,SUBPARTITION P1711sp1 ,
SUBPARTITION P1711sp2 , SUBPARTITION P1711sp3 ,
SUBPARTITION P1711sp4 , SUBPARTITION P1711sp5 ,
SUBPARTITION P1711sp6 , SUBPARTITION P1711sp7 ,
SUBPARTITION P1711sp8 , SUBPARTITION P1711sp9 ,
SUBPARTITION P1711sp10 , SUBPARTITION P1711sp11 ,
SUBPARTITION P1711sp12 , SUBPARTITION P1711sp13 ,
SUBPARTITION P1711sp14 , SUBPARTITION P1711sp15 ),