1、分区列索引约束
若表有primary key或unique key,则分区表的分区列必须包含在primary key或unique key列表里,这是为了确保主键的效率,否则同一主键区的东西一个在A分区,一个在B分区,显然会比较麻烦。
2、各分区类型条件
range 每个分区包含那些分区表达式的值位于一个给定的连续区间内的行。这些区间要连续且不能相互重叠
list只支持整形字段或返回整形数的表达式,每个分区列表里的值列表必须整数
hash类型只支持整形字段或返回整形数的表达式
key类型只支持列名形式(可一个或多个列名),不支持表达式
3、分区可用函数
ABS()
CEILING() (see CEILING() and FLOOR(), immediately following this list)
DAY()
DAYOFMONTH()
DAYOFWEEK()
DAYOFYEAR()
DATEDIFF()
EXTRACT()
FLOOR() (see CEILING() and FLOOR(), immediately following this list)
HOUR()
MICROSECOND()
MINUTE()
MOD()
MONTH()
QUARTER()
SECOND()
TIME_TO_SEC()
TO_DAYS()
WEEKDAY()
YEAR()
YEARWEEK()
注意:
因为分区函数不包括FROM_UNIXTIME函数,所以用时间戳转时间来分区就无法实现了,只能用date或者datetime来分区
例如按年我们可以用:
PARTITION BY RANGE (YEAR(date))
按月:
PARTITION BY RANGE(date div 100)
#div 会把日期变成整数,例如:2014-12-01 -> 20141201、100就是从后面去掉两位,最后结果是201412
一个订单做分区的例子:
CREATE TABLE `order` (
`order_id` bigint(19) NOT NULL DEFAULT '0' COMMENT '订单ID:年月日时分秒12位+7位随机数',
`date` date NOT NULL DEFAULT '0000-00-00' COMMENT '订单日期',
`amount` int(11) DEFAULT NULL COMMENT '支付金额,单位分',
`status` tinyint(1) DEFAULT '0' COMMENT '0:等待支付 1:支付成功 2:支付失败 3:验证失败',
`addtime` int(10) DEFAULT NULL COMMENT '订单添加时间',
PRIMARY KEY (`order_id`,`date`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
因为我们没法用时间戳来做按时间分区,所以添加了一个date字段,这个字段和order_id一起作为主键,我们知道分区的列一定要放到主键里面去的。下面我们用date计算成年月组合来分区
ALTER TABLE order PARTITION BY RANGE( date DIV 100)
(
PARTITION p_2014_06 VALUES LESS THAN (201407),
PARTITION p_2014_07 VALUES LESS THAN (201408),
PARTITION p_2014_08 VALUES LESS THAN (201409),
PARTITION p_2014_09 VALUES LESS THAN (201410),
PARTITION p_2014_10 VALUES LESS THAN (201411),
PARTITION p_catch_all VALUES LESS THAN MAXVALUE
);
以上 LESS THAN MAXVALUE 设置了最后一个分区p_catch_all,所以不能用add的方式来添加分区了,以下语句不可用:
ALTER TABLE order ADD PARTITION (PARTITION p_2014_11 VALUES LESS THAN (201412));
只能把最后的p_catch_all分区拆分成两个,这样还有一个好处就是在p_catch_all分区的数据不会丢失。数据的合并与拆分用REORGANIZE PARTITION进行。
alter table order reorganize partition p_catch_all into
(
partition p_2014_11 values less than (201412),
partition p_catch_all values less than maxvalue
);
合并分区:
alter table order reorganize partition p_2014_10,p_2014_11,p_catch_all into
(
partition p_catch_test values less than MAXVALUE
);
为什么不分到p_catch_all去?因为会报分区以存在。
为什么合并的时候要带上最后一个分区p_catch_all?因为除了最后一个分区,其他重组的分区范围不能改变总范围。
删除分区但是不删除数据:
alter table 表名 remove partitioning
注意:上面语句在5.5可以执行,5.6好像有问题,要先测试一下
分区之后,where条件是一个范围的话分区是不起作用的,如 where date >= '2014-01-01' And date <= '2014-01-31'
一定要用 = 或者 in 条件才行 where date = '2014-01-01' 或者 where date in ('2014-01-01', '2014-01-02', '2014-01-03'...)