按范围分区的MySQL分区表的每个底层表中存放能够匹配表达式的范围区间的数据。
分区范围必须是连续且不相互覆盖的。
分区范围必须使用VALUES LESS THAN
定义。
在下面的几个例子中,假设已经存在一个用来存放个人信息的表:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
);
我们可以使用多种方式将 employees
表进行分区,至于使用那种方式需要根据需要来选择。一种方式是,使用store_id
列来分区。例如,我们将employees
表分成四个底层表:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21),
);
在这种分区模式中,employees
中的1~5行存放在分区p0中, 6~10存放在p1,以此类推。
分区定义必须从低到高,按序定义。这是PARTITION BY RANGE语法要求的。。可以把分区定义想象成C或Java中的一组
if .. elseif ...
语句。
我们可以很轻松地判断出(72, ‘Mitchell’, ‘Wilson’, ‘1998-06-25’, NULL, 13)这行数据会插入到分区表p2中,但是当我们想要插入第21行数据时,会发生什么?现在的分区模式没有定义store_id
大于20的规则,服务器会因为不知道往哪个分区插入数据而报错。我们可以在定义规则时加上一个归总的VALUES LESS THAN
来避免这种情况:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE,
);
MAXVALUE
代表一个最大的整型值,永远比一个可能的整型数大。现在,任何store_id
大于等于16的行都会插入到分区p3。当employees
表中的数据增长到25~30个时,可以通过ALTER TABLE
语句来新增分区,用于存放21~25, 26~30的数据,等等。
同样的方式,我们可以基于job_code
列值得范围来对employees
表进行分区。假设,我们用两位数的job_code
来标记普通员工,三位数来标记行政和支持人员,四位数标记管理职位,我们可以创建下面的分区:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
PARTITION p0 VALUES LESS THAN (100),
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (10000)
);
在这个例子中,普通员工存在分区p0中,行政、支持员工存在p1,管理人员存在p2。
除了使用存放在字段中的值来进行范围分区,我们还可以对两个Date
类型使用表达式来进行分区。假设,我们希望对employees
表根据员工离职日期进行以年为单位的分区,我们可以使用函数YEAR(separated)
的值进行分区:
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (YEAR(separated))(
PARTITION p0 VALUES LESS THAN (1991),
PARTITION p1 VALUES LESS THAN (1996),
PARTITION p2 VALUES LESS THAN (2006),
PARTITION p2 VALUES LESS THAN (2016)
);
现在的规则中,1991年前离职的员工存放在分区p0, 1991~1995之间离职的在分区p1,1996~2005的在p2,2006~2015的在p3。
MySQL还允许是用UNIX_TIMESTAMP
函数进行分区:
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
范围分区对下面的应用场景特别有用:
EXPLAIN PARTITIONS SELECT COUNT(*) FORM employees where separated BETWEEN '2001-01-01' AND '2001-12-31'
, MySQL可以快速判断出来只有p2分区需要扫描,因为其他分区不会存在满足where
条件的数据。范围分区有一个列范围分区的变种。在这个变种中,允许使用多个列进行分区。
使用时间类型的整型值进行分区。下面是两个用DATE
,TIME
或者TIMESTAMP
的范围或者整型值进行分区的案例:
RANGE
进行分区。 在分区表达式中,我们对DATE
,TIME
或者TIMESTAMP
的数据使用函数,并利用函数返回的int值作为分区的依据:
CREATE TABLE members (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY RANGE( YEAR(joined) ) (
PARTITION p0 VALUES LESS THAN (1960),
PARTITION p1 VALUES LESS THAN (1970),
PARTITION p2 VALUES LESS THAN (1980),
PARTITION p3 VALUES LESS THAN (1990),
PARTITION p4 VALUES LESS THAN MAXVALUE
);
还可以使用UNIX_TIMESTAP()
函数的返回值来分区:
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
2. 使用RANGE COLUMN
进行分区。
例如,使用joined
字段对members
表进行分区:
CREATE TABLE members (
firstname VARCHAR(25) NOT NULL,
lastname VARCHAR(25) NOT NULL,
username VARCHAR(16) NOT NULL,
email VARCHAR(35),
joined DATE NOT NULL
)
PARTITION BY RANGE COLUMNS(joined) (
PARTITION p0 VALUES LESS THAN ('1960-01-01'),
PARTITION p1 VALUES LESS THAN ('1970-01-01'),
PARTITION p2 VALUES LESS THAN ('1980-01-01'),
PARTITION p3 VALUES LESS THAN ('1990-01-01'),
PARTITION p4 VALUES LESS THAN MAXVALUE
);
只有
DATE
,DATETIME
类型的字段才支持RANGE COLUMNS
分区。