MySQL分表--范围分区

MySQL分表–范围分区

按范围分区的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)
);

范围分区对下面的应用场景特别有用:

  • 删除旧数据。使用上面的分区,我可以使用’ALTER TABLE employees DROP PARTITION p0’来删除1991年前离职的员工记录。当表中记录非常多时,这个语句会比’DELETE FROM employees WHERE YEAR(separated) < 1991’的效率高很多。
  • 当使用包含日期、时间数据的列,或者包含增长数据的列。
  • 频繁执行直接依赖用于分区的列。例如,当执行EXPLAIN PARTITIONS SELECT COUNT(*) FORM employees where separated BETWEEN '2001-01-01' AND '2001-12-31', MySQL可以快速判断出来只有p2分区需要扫描,因为其他分区不会存在满足where条件的数据。

范围分区有一个列范围分区的变种。在这个变种中,允许使用多个列进行分区。

使用时间类型的整型值进行分区。下面是两个用DATE,TIME或者TIMESTAMP的范围或者整型值进行分区的案例:

  1. 使用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分区。

你可能感兴趣的:(mysql)