mysql 分区表优化_Sql优化之Mysql表分区
一??分區(qū)表適用于以下場景
1:表非常大以至于無法全部放在內(nèi)存中,或者只在標(biāo)的最后部分有熱點數(shù)據(jù),其他均是歷史數(shù)據(jù)
2:分區(qū)表的數(shù)據(jù)更容易維護(hù)。例如想批量刪除大量數(shù)據(jù)可以使用清除整個分區(qū)的方式。另外還可以對一個獨立分區(qū)進(jìn)行優(yōu)化、檢查、修復(fù)等操作。
3:分區(qū)表的數(shù)據(jù)可以分布在不同的物理設(shè)備上,從而高效的利用多個硬件設(shè)備
4:可以使用分區(qū)表來避免某些特殊的瓶頸。例如InnoDB的單個索引的互斥訪問、ext3文件系統(tǒng)的inode鎖競爭等。
5:如果需要,還可以備份和恢復(fù)獨立的分區(qū),這在非常大的數(shù)據(jù)集的場景下效果非常好。
二? 分區(qū)原理以及限制
mysql數(shù)據(jù)庫中的數(shù)據(jù)是以文件的形勢存在磁盤上的,默認(rèn)放在/mysql/data下面(可以通過my.cnf中的datadir來查看),一張表主要對應(yīng)著三個文件,一個是frm存放表結(jié)構(gòu)的,一個是myd存放表數(shù)據(jù)的,
一個是myi存表索引的。如果一張表的數(shù)據(jù)量太大的話,那么myd,myi就會變的很大,查找數(shù)據(jù)就會變的很慢,這個時候我們可以利用mysql的分區(qū)功能,
在物理上將這一張表對應(yīng)的三個文件,分割成許多個小塊,這樣呢,我們查找一條數(shù)據(jù)時,就不用全部查找了,只要知道這條數(shù)據(jù)在哪一塊,然后在那一塊找就行了。
如果表的數(shù)據(jù)太大,可能一個磁盤放不下,這個時候,我們可以把數(shù)據(jù)分配到不同的磁盤里面去。
分區(qū)表的限制
分區(qū)表的原理
SELECT 查詢:當(dāng)查詢一個分區(qū)表的時候,分區(qū)層先打開并鎖住所有底層表,優(yōu)化器先判斷是否可以過濾部分分區(qū),然后再調(diào)用對應(yīng)的存儲引擎接口訪問各個分區(qū)的數(shù)據(jù);
INSERT操作:當(dāng)寫入一條數(shù)據(jù)時,分區(qū)層先打開并鎖住所有的底層表,然后確定那個分區(qū)接收這條數(shù)據(jù),然后再將記錄寫入對應(yīng)的底層表;
DELETE操作:當(dāng)刪除一條記錄時,分區(qū)層現(xiàn)代開并鎖住所有的底層表,然后確定數(shù)據(jù)對應(yīng)的分區(qū),最后對相應(yīng)底層進(jìn)行刪除操作;
UPDATE操作:當(dāng)更新一條記錄時,分區(qū)層先打開并鎖住所有的底層表,MYSQL先確定需要更新的記錄在哪個分區(qū),然后取出數(shù)據(jù)并更新,在判斷更新后的數(shù)據(jù)應(yīng)該放在哪個分區(qū),最后對底層表進(jìn)行寫入操作,并對原數(shù)據(jù)所在的底層表進(jìn)行刪除操作。
當(dāng)然其中有些操作是支持過濾的。例如當(dāng)刪除一條記錄時,MYSQL 需要先找到這條記錄,如果where條件恰好和分區(qū)表達(dá)式匹配,就可以將所有不包含這條記錄的分區(qū)都過濾掉。同樣的操作對于update同樣有效。如果是insert操作,其本身就是只命中一個分區(qū) ,其他分區(qū)都會被過濾掉。MYSQL先確定這條記錄屬于哪個分區(qū),再將記錄寫入對應(yīng)的底層分區(qū)表,無須對任何其他分區(qū)進(jìn)行操作。(雖然每個操作都會“”“先打開并鎖住所有的底層表”,但是并不是說分區(qū)表在處理過程中是鎖住全表的,如果存儲引擎能夠自己實現(xiàn)行級鎖,例如InnoDB,則會在分區(qū)層釋放對應(yīng)表鎖)。
分區(qū)表的類型:MYSQL支持多種分區(qū)表
最常見的就是根據(jù)范圍進(jìn)行分區(qū),每個分區(qū)存儲落在某個范圍的記錄,分區(qū)表達(dá)式可以是列,也可以是列的表達(dá)式。下面的例子是將每一年的銷售額存放在不同的分區(qū)里。
三? ? 創(chuàng)建分區(qū)操作
RANGE分區(qū):
mysql> CREATE TABLE `operation_log` (
-> `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
-> `cid` mediumint(7) unsigned NOT NULL,
-> `accountid` mediumint(8) NOT NULL DEFAULT '0' ,
-> `flag` tinyint(1) unsigned NOT NULL DEFAULT '0',
-> `addtime` int(11) unsigned NOT NULL,
-> `device` tinyint(1) unsigned NOT NULL DEFAULT '1' ,
-> PRIMARY KEY (`id`,`addtime`),
-> KEY `idx_accountid_addtime` (`accountid`,`addtime`),
-> KEY `idx_accountid_flag` (`accountid`,`flag`),
->) ENGINE=InnoDB AUTO_INCREMENT=50951039 DEFAULT CHARSET=utf8 COMMENT='操作記錄'
->/*!50100 PARTITION BY RANGE (addtime)
->(PARTITION `2013-05` VALUES LESS THAN (1370016000) ENGINE = InnoDB,
-> PARTITION `2013-06` VALUES LESS THAN (1372608000) ENGINE = InnoDB,
-> PARTITION `2013-07` VALUES LESS THAN (1375286400) ENGINE = InnoDB,
-> PARTITION `2013-08` VALUES LESS THAN (1377964800) ENGINE = InnoDB,
-> PARTITION `2013-09` VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */;
1 row in set (0.00 sec)
( LESS THAN MAXVALUE考慮到可能的最大值)
list分區(qū)
//這種方式失敗
mysql> CREATE TABLE IF NOT EXISTS `list_part` (
-> `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '用戶ID',
-> `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',
-> `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名稱',
-> `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0為男,1為女',
-> PRIMARY KEY (`id`)
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
-> PARTITION BY LIST (province_id) (
-> PARTITION p0 VALUES IN (1,2,3,4,5,6,7,8),
-> PARTITION p1 VALUES IN (9,10,11,12,16,21),
-> PARTITION p2 VALUES IN (13,14,15,19),
-> PARTITION p3 VALUES IN (17,18,20,22,23,24)
-> );
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
//這種方式成功
mysql> CREATE TABLE IF NOT EXISTS `list_part` (
-> `id` int(11) NOT NULL COMMENT '用戶ID',
-> `province_id` int(2) NOT NULL DEFAULT 0 COMMENT '省',
-> `name` varchar(50) NOT NULL DEFAULT '' COMMENT '名稱',
-> `sex` int(1) NOT NULL DEFAULT '0' COMMENT '0為男,1為女'
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8
-> PARTITION BY LIST (province_id) (
-> PARTITION p0 VALUES IN (1,2,3,4,5,6,7,8),
-> PARTITION p1 VALUES IN (9,10,11,12,16,21),
-> PARTITION p2 VALUES IN (13,14,15,19),
-> PARTITION p3 VALUES IN (17,18,20,22,23,24)
-> );
Query OK, 0 rows affected (0.33 sec)
上面的這個創(chuàng)建list分區(qū)時,如果有主銉的話,分區(qū)時主鍵必須在其中,不然就會報錯。如果我不用主鍵,分區(qū)就創(chuàng)建成功了,一般情況下,一個張表肯定會有一個主鍵,這算是一個分區(qū)的局限性
hash分區(qū)
mysql> CREATE TABLE IF NOT EXISTS `hash_part` (
-> `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '評論ID',
-> `comment` varchar(1000) NOT NULL DEFAULT '' COMMENT '評論',
-> `ip` varchar(25) NOT NULL DEFAULT '' COMMENT '來源IP',
-> PRIMARY KEY (`id`)
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1
-> PARTITION BY HASH(id)
-> PARTITIONS 3;
Query OK, 0 rows affected (0.06 sec)
key分區(qū)
mysql> CREATE TABLE IF NOT EXISTS `key_part` (
-> `news_id` int(11) NOT NULL COMMENT '新聞ID',
-> `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新聞內(nèi)容',
-> `u_id` varchar(25) NOT NULL DEFAULT '' COMMENT '來源IP',
-> `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '時間'
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8
-> PARTITION BY LINEAR HASH(YEAR(create_time))
-> PARTITIONS 3;
Query OK, 0 rows affected (0.07 sec)
增加子分區(qū)操作
子分區(qū)是分區(qū)表中每個分區(qū)的再次分割,子分區(qū)既可以使用HASH希分區(qū),也可以使用KEY分區(qū)。這 也被稱為復(fù)合分區(qū)(composite partitioning)
1. 如果一個分區(qū)中創(chuàng)建了子分區(qū),其他分區(qū)也要有子分區(qū)
2. 如果創(chuàng)建了了分區(qū),每個分區(qū)中的子分區(qū)數(shù)必有相同
3. 同一分區(qū)內(nèi)的子分區(qū),名字不相同,不同分區(qū)內(nèi)的子分區(qū)名子可以相同(5.1.50不適用)
1
2
3
4
5
6
7
8
9
10
11
12
13
mysql> CREATE TABLE IF NOT EXISTS `sub_part` (
-> `news_id` int(11) NOT NULL COMMENT '新聞ID',
-> `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '新聞內(nèi)容',
-> `u_id` int(11) NOT NULL DEFAULT 0s COMMENT '來源IP',
-> `create_time` DATE NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '時間'
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8
-> PARTITION BY RANGE(YEAR(create_time))
-> SUBPARTITION BY HASH(TO_DAYS(create_time))(
-> PARTITION p0 VALUES LESS THAN (1990)(SUBPARTITION s0,SUBPARTITION s1,SUBPARTITION s2),
-> PARTITION p1 VALUES LESS THAN (2000)(SUBPARTITION s3,SUBPARTITION s4,SUBPARTITION good),
-> PARTITION p2 VALUES LESS THAN MAXVALUE(SUBPARTITION tank0,SUBPARTITION tank1,SUBPARTITION tank3)
-> );
Query OK, 0 rows affected (0.07 sec)
分區(qū)管理
增加分區(qū)操作(針對設(shè)置MAXVALUE)
range添加分區(qū)
1
2
3
mysql>alter table operation_log add partition(partition `2013-10` values less than (1383235200)); --->適用于沒有設(shè)置MAXVALUE的分區(qū)添加
ERROR 1481 (HY000):MAXVALUE can only be used in last partition definition
mysql>alter table operation_log REORGANIZE partition `2013-09` into (partition `2013-09` values less than (1380556800),partition `2013-10` values less than (1383235200),partition `2013-11` values less than maxvalue);
list添加分區(qū)
1
2
3
mysql> alter table list_part add partition(partition p4 values in (25,26,28));
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
hash重新分區(qū)
1
2
3
mysql> alter table list_part add partition(partition p4 values in (25,26,28));
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
key重新分區(qū)
1
2
3
mysql> alter table key_part add partition partitions 4;
Query OK, 1 row affected (0.06 sec)//有數(shù)據(jù)也會被重新分配
Records: 1 Duplicates: 0 Warnings: 0
子分區(qū)添加新分區(qū),雖然我沒有指定子分區(qū),但是系統(tǒng)會給子分區(qū)命名的
1
2
3
mysql> alter table sub1_part add partition(partition p3 values less than MAXVALUE);
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
刪除分區(qū)操作
alter table user drop partition2013-05;
分區(qū)表其他操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
重建分區(qū)(官方:與先drop所有記錄然后reinsert是一樣的效果;用于整理表碎片)
alter table operation_log rebuild partition `2014-01`;
重建多個分區(qū)
alter table operation_log rebuild partition `2014-01`,`2014-02`;
過程如下:
pro
優(yōu)化分區(qū)(如果刪除了一個分區(qū)的大量記錄或者對一個分區(qū)的varchar blob text數(shù)據(jù)類型的字段做了許多更新,此時可以對分區(qū)進(jìn)行優(yōu)化以回收未使用的空間和整理分區(qū)數(shù)據(jù)文件)
alter table operation_log optimize partition `2014-01`;
優(yōu)化的操作相當(dāng)于check partition,analyze partition 和repair patition
分析分區(qū)
alter table operation_log analyze partition `2014-01`;
修復(fù)分區(qū)
alter table operation_log repair partition `2014-01`;
檢查分區(qū)
alter table operation_log check partition `2014-01`;
總結(jié)
以上是生活随笔為你收集整理的mysql 分区表优化_Sql优化之Mysql表分区的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python gevent缺点_pyth
- 下一篇: mysql带c的命令_mysql命令整理