22章分区

目录

22.1分区概述MySQL
22.2分区类型
22.2.1范围划分
22.2.2列表分区
22.2.3栏目划分
22.2.4 hash分解
22.2.5密钥分配
22.2.6分区
22.2.7 MySQL如何分割处理空
22.3分区管理
22.3.1管理范围和列表分区
22.3.2哈希分区管理和重点
22.3.3交换分区和子分区表
22.3.4维护分区
22.3.5获得信息的分区
22.4分区修剪
2.2.5分区选择
在分区22.6限制
原发性22.6.1分解钥匙和钥匙,钥匙,特制
22.6.2划分的局限性与存储引擎
22.6.3划分的局限性与功能

本章讨论用户自定义分区

笔记

表分区划分为不同的窗口函数的使用。对窗函数的信息,参见12.20节,“窗口”功能

在MySQL 5.0,分区支持由InnoDB存储引擎。(TheNDBMySQL集群使用的存储引擎还提供了分区的支持,但NDB不包含在MySQL 8。)

MySQL 5.0目前不支持使用其他存储引擎的表分区InnoDB,如MyISAM。尝试使用一个存储引擎,不提供本地分区支持失败,创建一个分区表er_check_not_implemented

MySQL社区8二进制文件由Oracle提供的包括分割提供的支持InnoDB存储引擎。关于分区在MySQL企业版的二进制文件提供支持的信息,参见29章,MySQL企业版

如果你正在编写的MySQL 8从源,配置建设InnoDB支持足以产生分区支持二进制文件InnoDB表有关更多信息,参见2.8节,从“源”安装MySQL

没有什么需要做进一步使分区支持InnoDB(例如,没有特殊要求的项目my.cnf文件)

它不可能禁用分区的支持InnoDB存储引擎

看到22.1节,“MySQL”分区概述,为分区和分区的概念介绍。

几个分区类型的支持,以及看到分区;22.2节,“分区类型”,和第22.2.6,“subpartitioning”

第22,“分区管理”方法,包括添加,删除,和改变现有的分区表的分区。

第22.3.4,“维护分区”,讨论了使用分区表表的维护命令。

这个PARTITIONS表中information_schema数据库提供了有关分区和分区表。看到24.14节,“information_schema分区表”,更多的信息;对于一些对这个表的查询的例子,看第22.2.7,“MySQL如何分割处理空”

已知问题与MySQL 5.0分区,看22.6节,“分区”的约束和限制

你也可能会发现下面的资源是有用的工作分区表时。

额外资源其他来源的信息对用户自定义分区在MySQL中包括以下内容:

22.1分区概述MySQL

本节提供了在MySQL 8分区的概念性概述。

在分区的限制和功能的限制的信息,参见22.6节,“分区”的约束和限制

SQL标准并没有提供太多的指导方式对于数据存储的物理方面。SQL语言本身的目的是独立工作的任何数据结构或媒体相关的图式、表、行或列,它的作品。然而,最先进的数据库管理系统的发展,确定物理位置可用于存储在文件系统上的数据的特定部分的一些手段,硬件甚至都。在MySQL的InnoDB存储引擎一直支持一个表空间的概念(见15.7节,“InnoDB表空间”),和MySQL服务器,甚至划分出台之前,可以配置为使用不同的物理目录用于存储不同的数据库(见第8.12.2,“使用符号链接”,一个解释如何做到这一点)。

分区以这一概念更进了一步,允许你发布个人表在文件系统的部分,根据规则,你可以设置在很大程度上需要。实际上,一个表的不同部分在不同的位置被存储为单独的表。用户选择规则的数据划分完成了被称为分区函数,在MySQL可以模,简单的匹配对一个集合的范围或值列表,一个内部的哈希函数,或线性散列函数。其功能是根据用户指定的分区类型的选择,以及作为其参数的用户提供的表达式的值。这种表达可以列值,作用于一个或多个列的值的函数,或一组一个或多个列的值,根据不同的类型划分,用。

在的情况下RANGE列表,和[LINEAR]搞砸分区,分区列的值是通过分区函数,它返回一个整型值表示数量的分区中,特定的记录应保存。这个函数必须是恒定的,非随机的。它可能不包含任何查询,但可以使用一个SQL表达式,在MySQL中是有效的,只要表达返回NULL或一个整数intval这样,

-MAXVALUE <=intval<= MAXVALUE

MAXVALUE是用来表示整数类型的问题的最小上界。- MaxValue代表最大下界。)

[原件:英文]LINEAR]钥匙RANGE COLUMNS,和表列分区,分区表达式由一个或多个列。

[原件:英文]LINEAR]钥匙分区,分区函数是由MySQL。

为更多的信息关于允许分区列类型和分区功能,看22.2节,“分区类型”,以及第13.1.18,“创建表的语法,提供分区的语法描述和附加的例子。关于分区功能限制的信息,参见第22.6.3,分区限制有关的功能”

这是被称为水平切分即不同的表中的行可以被分配到不同的物理分区。MySQL 8不支持垂直分区,其中表不同的列被分配到不同的物理分区。目前暂时没有计划引入垂直分割成MySQL。

创建分区表,你必须使用一个支持他们的存储引擎。在MySQL 8中,所有分区的分区表必须使用相同的存储引擎。然而,没有什么能够阻止你使用不同的存储引擎的不同分区表相同的MySQL服务器,甚至在同一个数据库。

在MySQL 8中,唯一的存储引擎,支持分区InnoDB。分区不能用于不支持它的存储引擎;这些包括MyISAMMERGECSV,和FEDERATED存储引擎

创建一个分区表时,默认的存储引擎只是作为创建任何其他表的时候;重写此行为,只需使用[STORAGE] ENGINE选择就如同未分区表。目标存储引擎必须提供本地分区的支持,或语句失败。你应该记住【贮藏】发动机(和其他表需要列出选项)之前任何分区选项中使用CREATE TABLE声明。这个例子显示了如何创建一个表,按哈希分区为6个分区,使用InnoDB存储引擎(无论其价值default_storage_engine):

CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)    ENGINE=INNODB    PARTITION BY HASH( MONTH(tr_date) )    PARTITIONS 6;

每个PARTITION条款可以包括【贮藏】发动机的选择,但在MySQL 5.0这没有影响。

除非另有规定,在这次讨论中剩余的例子假设default_storage_engineInnoDB

重要

适用于所有数据和分区表索引;你不能分区只有数据而没有指标,或反之亦然,你也不能分区只有部分表。

每个分区的数据和指标可以分配到一个特定的目录使用DATA DIRECTORY索引目录可供选择的PARTITION的条款CREATE TABLE语句用于创建分区表

只有DATA DIRECTORY选择是个人的分区和子分区支持InnoDB

用表中的所有列必须分区表达每一个独特的关键,表可能有一部分,包括任何主键。这意味着一台这样的,通过下面的SQL语句创建,不能分解:

CREATE TABLE tnp (
    id INT NOT NULL AUTO_INCREMENT,
    ref BIGINT NOT NULL,
    name VARCHAR(255),
    PRIMARY KEY pk (id),
    UNIQUE KEY uk (name)
);

因为钥匙pk英国没有共同的列,也可用于分区表达无柱。在这种情况下,可能的解决方法包括添加name柱表的主键,添加身份证件uk,或者干脆删除UNIQUE键共。看到“22.6.1分解段,原钥匙,钥匙和钥匙,独特的”为更多的信息

此外,MAX_ROWSmin_rows可以用来确定最大和最小行数,分别可以存储在每个分区。看到第22,“分区管理”有关这些选项的更多信息。

分区的一些优点如下:

  • 分区可以存储更多的数据比一台可以在单个磁盘或文件系统分区举行。

  • 数据,失去它的实用性往往可以删除分区容易从分区表中删除(或分区)只包含数据。相反,添加新数据的过程可以在某些情况下增加一个或多个存储具体数据分区提供了极大的便利。

  • 一些查询可以在事实上,满足一个给定的数据极大地优化WHERE子句只能存储在一个或多个分区,可自动排除任何剩余的分区从搜索。因为分区可以在分区表已经改变,你可以整理你的数据提升频繁的查询,可能没有被使用时,分区方案成立。这种能力来排除非匹配的分区(因此它们包含任何行)通常被称为分区裁剪。有关更多信息,参见22.4节,“分区修剪”

    此外,为支持MySQL查询明确分区选择。例如,SELECT * FROM t PARTITION (p0,p1) WHERE c < 5只选择分区中的行P0p1那场比赛的哪里条件在这种情况下,MySQL不检查任何其他分区表t;这可以大大加快查询的时候,你已经知道哪个分区或分区你希望检查。分区选择也是支持的数据修改语句DELETEINSERTREPLACEUPDATE,和LOAD DATALOAD XML。看到这些语句的更多信息和示例说明。

分区的其他好处包括那些通常在以下列表。这些特点是不是目前在MySQL分区实施,但是我们优先考虑的事情。

  • 包括聚合函数的查询等SUM()COUNT()可以很容易地进行并行处理。一个简单的这样一个查询的例子可能是选择salesperson_id,计数(订单)为order_total销售组salesperson_id;。由并行化,我们指的查询可以在每个分区上同时运行,并最终通过了所有分区的结果仅仅是获得。

  • 在实现数据查询吞吐量寻求更大的传播借助于多个磁盘。

22.2分区类型

本节讨论的分区可在MySQL 8类型。这些包括以下类型:

  • 范围分区这种类型的分区分配行基于列值的下降在一定范围内的分区。看到第22.2.1,”范围划分”。关于这种类型的扩展信息,RANGE COLUMNS,看到第22.2.3.1,范围列分区”

  • 列表分区类似的分区RANGE,除了分区是基于匹配的一组离散的值选择列。看到22.2.2节,“列表分区”。关于这种类型的扩展信息,LIST COLUMNS,看到第22.2.3.2,”名单列分区”

  • 哈希分区这种类型的分区,一个分区是基于价值的一个用户定义的表达上运行的行中的列值将被插入到选定的表返回。该功能可以由任何表达有效的MySQL中产生一个非负整数的值。这种类型的扩展,LINEAR HASH,也可查阅。见第22.2.4,“哈希分区”

  • 密钥分割这种类型的划分与分区HASH,但只有一个或多个列进行供给,和MySQL服务器提供自己的哈希函数。这些列可以包含其他非整数的值,因为散列函数提供的MySQL保证整数结果的列的数据类型。这种类型的扩展,线性键,is also available。See第22.2.5,“重点分配”

一个很常见的使用数据库分区是将数据按日期。一些数据库系统支持明确的日期划分,MySQL不实现在8。然而,这是不难在MySQL创建分区方案的基础上DATETIME,或DATETIME列,或基于表达式利用这样的列。

当分区KEY线性键,你可以使用一个DATETIME,或DATETIME列作为分区列的列值不进行任何修改。例如,该表的创建语句MySQL是完全有效的:

创建表的成员(firstName varchar(25)不为空,lastName varchar(25)不为空,用户名varchar(16)不为空,varchar(35),加入邮件日期不为空)分区键(加入)分区6;

在MySQL 8中,也可以使用DATEDATETIME列作为分区列使用范围列LIST COLUMNS分区

其他的分区类型需要分配一个整型值或表达式NULL。如果你想使用基于划分的日期范围LIST搞砸,或LINEAR HASH你可以简单的使用功能,在操作DATETIME,或DATETIME柱和返回一个值,如下所示:

创建表的成员(firstName varchar(25)不为空,lastName varchar(25)不空,不空用户名varchar(16),电子邮件varchar(35),加入日期不为空)按范围分区(年(加入)(分区)P0值小于(1960年),分区P1值小于(1970年),分区P2的值小于(1980年),分区P3值小于(1990年),分区P4值小于最大值);

分区使用日期,额外的例子可以在本章接下来的部分找到:

对基于划分的日期更复杂的例子,看下面的部分:

MySQL分区的优化使用TO_DAYS()YEAR(),和TO_SECONDS()功能.然而,你可以使用其他的日期和时间函数返回一个整数或无效的,如WEEKDAY()DAYOFYEAR(),或MONTH()。看到12.7节,“戴特和时间函数”,有关该功能的更多信息。

它是要记住无论类型划分,你将总是使用自动编号和序列创建时的重要,开始0。当一个新的行插入到分区表,正是这些分区号是用于识别正确的分区。例如,如果你的表使用的分区,这些分区编号1,和3。对于范围LIST分区类型,要确保有一个为每个分区的分区数的定义。为搞砸分区,用户提供的表达式的值必须是一个整数的值大于0。为钥匙分区,这个问题是照顾自动的散列函数,MySQL服务器使用内部。

名称分区一般遵循其他MySQL标识符的规则,比如表和数据库。然而,你应该注意,分区名称不区分大小写。例如,下面的CREATE TABLE语句失败,如图所示:

MySQL的&#62;CREATE TABLE t2 (val INT)-&#62;PARTITION BY LIST(val)(-&#62;PARTITION mypart VALUES IN (1,3,5),-&#62;PARTITION MyPart VALUES IN (2,4,6)-&#62;);错误1488(hy000):复制分区的名字10.

故障发生时因为MySQL看到分区名称之间没有区别mypart10.

当你指定分区的数量为表,这必须被表达为阳性,非零整数没有前导零,而且可能是表达如0.8E+016-2,即使它对一个整数。小数是不允许的。

在接下来的章节中,我们不一定提供一切可能的语法可以用来创建每个分区类型形式;这个信息,看第13.1.18,“创建表的语法

22.2.1范围划分

已分区表的分区范围是以这样一种方式,每个分区包含的行为分区表达式的值是一个给定的范围内。范围应连续但不重叠,和定义使用VALUES LESS THAN算子。在接下来的几个例子,假设你正在创建一个表,如以下为20家连锁音像店举行的人事档案,编号为1到20:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int不空,不空store_id int);
笔记

这个employees表用在这里没有主键或唯一键。而工作的例子如图所示的当前讨论的目的,你应该记住,表是极有可能在实践中有主键,外键,或两者,分区列允许的选择取决于使用这些键的列,如果存在。对于这些问题的讨论,见“22.6.1分解段,原钥匙,钥匙和钥匙,独特的”

这张桌子可以按范围分区的多种方式,根据你的需要。一种方法是使用store_id专栏例如,你可能决定分区表的方式加入按范围分区条款如下所示:

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)
);

在这个分区方案,所有行相应的员工工作在商店1-5都存储在分区p0,那些在商店通过10 6存储分区P1,等等。每个分区被定义为,从最低到最高。这是一个要求PARTITION BY RANGE语法;你可以认为它是类似于一个系列如果…“…在这方面,C和java报表。

这是很容易确定一个新的行包含数据(72, 'Mitchell', 'Wilson', '1998-06-25', NULL, 13)插入分区P2但当你的外链,增加了21ST商店根据这项计划,没有规则,涵盖了一个排的store_id大于20,所以错误的结果因为服务器不知道哪里的地方。你可以把这个利用了从发生包罗万象的VALUES LESS THAN子句中CREATE TABLE声明,提供所有值大于最高值显式命名:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int不空,不空store_id int)按范围分区(分区store_id)(P0值小于(6),分区P1值小于(11),分区P2的值小于(16),p3分区值小于最大);

(如在这一章中,其他的例子,我们假设默认存储引擎InnoDB。)

笔记

另一种方式来避免错误时,没有匹配的值被发现是使用IGNORE关键词的一部分INSERT声明。例如,看22.2.2节,“列表分区”。也看到了第13.2.6,“插入语法”对于一般的信息,IGNORE

MAXVALUE代表一个整数的值总是大于整数值最大(数学语言,它作为一个最小上界)。现在,任何行的store_id列的值大于或等于16(最高值定义)都存储在分区P3。在未来的某一时刻,当门店数量增加到了25,30,或您可以使用ALTER TABLE语句添加新分区存储21-25,26-30,等等(见第22,“分区管理”,细节如何做到这一点)。

以同样的方式,你可以根据员工的工作守则,是表分区,基于范围job_code列的值。例如,假设两位数的工作代码用于正则(店内)的工人,三位码是用于办公和支持人员,和四位数字码用于管理职位,你可以使用下面的语句创建分区表:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int不空,不空store_id int)按范围分区(分区job_code)(P0值小于(100),分区P1值小于(1000),分区P2的值小于(10000));

在这种情况下,所有行有关商店的工人将被存储在分区p0,与办公室和支持人员P1,和那些有关管理分区p2

它也可以使用的表达VALUES LESS THAN条款.然而,MySQL必须能够评估表达式的返回值的一部分小于<比较)

而不是分裂的表数据根据商店的数量,你可以使用基于一个表达式DATE柱代替。例如,让我们假设你希望分区基于年每个员工离开公司;即价值YEAR(separated)。一例CREATE TABLE声明说,实施这样的分区方案如下所示:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int,int store_id)按范围分区(年(分离)(分区)P0值小于(1991),分区P1值小于(1996),分区P2的值小于(2001),分区P3值小于最大值);

在这个方案中,所有的员工离开之前,1991年的行存储在分区p0;对于那些留在年1991至1995,在P1;对于那些留在年1996至2000,在p2;和谁离开了2000年后的任何人员,在P3

也有可能是分区表RANGE,基于一个价值TIMESTAMP柱,使用UNIX_TIMESTAMP()功能,如本例所示:

创建表quarterly_report_status(report_id int不空,report_status varchar(20)不空,不空report_updated时间戳默认current_timestamp更新current_timestamp)按范围分区(unix_timestamp(report_updated))(分区P0值小于(unix_timestamp(&#39;2008-01-01 00:00:00”)),分区P1值小于(unix_timestamp(&#39;2008-04-01 00:00:00”)),分区P2的值小于(unix_timestamp(&#39;2008-07-01 00:00:00”)),分区P3值小于(unix_timestamp(&#39;2008-10-01 00:00:00”)),分区P4值小于(unix_timestamp(&#39;2009-01-01 00:00:00”)),分区P5值小于(unix_timestamp(&#39;2009-04-01 00:00:00”)),分区P6值小于(unix_timestamp(&#39;2009-07-01 00:00:00”)),分区P7值小于(unix_timestamp(&#39;2009-10-01 00:00:00”)),分区P8值小于(unix_timestamp(&#39;2010-01-01 00:00:00”)),分区P9值小于(次));

其他表达式TIMESTAMP价值观是不允许的。(见虫# 42849。)

范围分区是特别有用的以下一个或多个条件为真时:

在这类划分的一个变种是RANGE COLUMNS分配。分配的村庄范围列可以使用多个列定义划分范围,既适用于排在分区布局和确定包含或排除特定的分区进行分区修剪时。看到第22.2.3.1,范围列分区”为更多的信息

基于时间间隔的分区方案。如果你想实现一个分区方案基于MySQL的8时间范围或时间,你有两个选择:

  1. 分区表RANGE,和分区的表达,采用功能操作上DATETIME,或DATETIME柱并返回一个整型值,如下所示:

    创建表的成员(firstName varchar(25)不为空,lastName varchar(25)不空,不空用户名varchar(16),电子邮件varchar(35),加入日期不为空)按范围分区(年(加入)(分区)P0值小于(1960年),分区P1值小于(1970年),分区P2的值小于(1980年),分区P3值小于(1990年),分区P4值小于最大值);

    在MySQL 8中,还可以通过分区表RANGE一种基于价值TIMESTAMP柱,使用UNIX_TIMESTAMP()功能,如本例所示:

    创建表quarterly_report_status(report_id int不空,report_status varchar(20)不空,不空report_updated时间戳默认current_timestamp更新current_timestamp)按范围分区(unix_timestamp(report_updated))(分区P0值小于(unix_timestamp(&#39;2008-01-01 00:00:00”)),分区P1值小于(unix_timestamp(&#39;2008-04-01 00:00:00”)),分区P2的值小于(unix_timestamp(&#39;2008-07-01 00:00:00”)),分区P3值小于(unix_timestamp(&#39;2008-10-01 00:00:00”)),分区P4值小于(unix_timestamp(&#39;2009-01-01 00:00:00”)),分区P5值小于(unix_timestamp(&#39;2009-04-01 00:00:00”)),分区P6值小于(unix_timestamp(&#39;2009-07-01 00:00:00”)),分区P7值小于(unix_timestamp(&#39;2009-10-01 00:00:00”)),分区P8值小于(unix_timestamp(&#39;2010-01-01 00:00:00”)),分区P9值小于(次));

    在MySQL 8中,任何其他表达式TIMESTAMP价值观是不允许的。(见虫# 42849。)

    笔记

    它也有可能在使用MySQL 8UNIX_TIMESTAMP(timestamp_column)expression as a for that are partitioned分解表模式列表。然而,它通常是不这样做的实际。

  2. 分区表RANGE COLUMNS,使用DATEDATETIME列作为分区列。例如,在会员表可以定义使用joined柱直接,如下所示:

    创建表的成员(firstName varchar(25)不为空,lastName varchar(25)不为空,用户名varchar(16)不为空,varchar(35),加入邮件日期不为空)的范围列分区(加入)(分区P0值小于(&#39;1960-01-01 &#39;),分区P1值小于(&#39;1970-01-01 &#39;),分区P2的值小于(&#39;1980-01-01 &#39;),分区P3值小于(&#39;1990-01-01 &#39;),分区P4值小于最大值);
笔记

使用分区列使用日期或时间比其他类型的DATEDATETIME不支持范围列

22.2.2列表分区

列表分区在MySQL是类似于在许多方面划分范围。在分区RANGE,每个分区必须被明确定义。这两种类型的分区之间的主要差别是,在列表分区,每个分区的定义和基于列值的会员在一组值的列表中选择,而不是一组值的连续范围。这是通过使用列表分区(expr哪里expr是一个列值或基于列的值并返回一个整型值的表达式,然后确定每个分区的值(value_list,在那里value_list是一个用逗号分隔的整数。

笔记

在MySQL 8中,它是可能的对手只有一个整数列表(可能NULL第22.2.7,“MySQL如何分割处理空”当分区)LIST

然而,其他列类型可以用在值列表时使用LIST COLUMN分配,这是在本节后面介绍。

与定义的范围分区列表分区的情况下,不需要任何特定的顺序声明。更详细的语法信息,看第13.1.18,“创建表的语法

在下面的例子中,我们假设的表进行分区的基本定义是由CREATE TABLE表所示:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code store_id int,int);

(这是作为一个基础的实例在同一台第22.2.1,”范围划分”。与其他分区的例子,我们假设default_storage_engineInnoDB。)

假定有20个音像店分布在4的专营权,如下表所示。

地区商店的ID号码
3, 5, 6,9, 17
1,2、10、11、19、20
西4, 12, 13,14, 18
中央7,8,15,16

在这样一种方式,行店属于同一地区存储在同一个分区表的分区,你可以使用CREATE TABLE表所示:

创建员工信息表(ID为不空,名varchar(30)、lname VARCHAR(30),雇用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code store_id int,int)列表分区(store_id)(分区pnorth值(3,5,6,9,17),分区peast值(1,2,10,11,19,20),分区pwest值(4,12,13,14,18),分区pcentral值(7,8,15,16));

这使得它很容易添加或删除员工记录有关特定地区或从表。例如,假设在西部地区的所有商店都出售给另一家公司。MySQL中的所有行为,涉及员工在该地区的商店工作可以删除与查询ALTER TABLE employees TRUNCATE PARTITION pWest,可以执行比更有效DELETE陈述从员工那里store_id删除(4,12,13,14,18);。(使用ALTER TABLE employees DROP PARTITION pWest还将删除所有这些行,但也将删除的分区pwest从表的定义;你将需要使用一个ALTER TABLE ... ADD PARTITION声明恢复表的分区方案。)

RANGE分区,它是可能的结合列表通过散列或关键生产复合分区分区的分区(分区)。看到第22.2.6,“subpartitioning”

与案例RANGE分区,没有抓住所有MAXVALUE;所有预期值为分区表达应覆盖分区…在values(…)条款.一个INSERT含有一个无与伦比的分区列的值不能用一个错误的声明,如本例所示:

MySQL的&#62;CREATE TABLE h2 (-&#62;c1 INT,-&#62;c2 INT-&#62;)-&#62;PARTITION BY LIST(c1) (-&#62;PARTITION p0 VALUES IN (1, 4, 7),-&#62;PARTITION p1 VALUES IN (2, 5, 8)-&#62;);查询行,0行受影响(0.11秒)MySQL &#62;INSERT INTO h2 VALUES (3, 5);错误1525(hy000):表没有分区的价值

当插入多行,使用一个单一的INSERT声明为一个单一的InnoDB表,InnoDB考虑语句的一单交易,所以任何无与伦比的价值的存在导致语句完全失败,所以没有行插入。

你能使这类错误被忽略的利用IGNORE关键词如果你这样做,含有无与伦比的分区列值的行不插入任何行,但与匹配值插入,并没有报告错误:

mysql> TRUNCATE h2;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM h2;
Empty set (0.00 sec)

mysql> INSERT IGNORE INTO h2 VALUES (2, 5), (6, 10), (7, 5), (3, 1), (1, 9);
Query OK, 3 rows affected (0.00 sec)
Records: 5  Duplicates: 2  Warnings: 0

mysql> SELECT * FROM h2;
+------+------+
| c1   | c2   |
+------+------+
|    7 |    5 |
|    1 |    9 |
|    2 |    5 |
+------+------+
3 rows in set (0.00 sec)

MySQL 8还提供了支持LIST COLUMNS分区,变体列表分区可以使用比其他分区列的整数类型的列,并使用多个列作为分区键。有关更多信息,参见第22.2.3.2,”名单列分区”

22.2.3栏目划分

接下来的两节中讨论COLUMNS分区,这是变异范围LIST分区专栏用户可以使用多个分区键列。所有这些列都考虑到将排在分区的目的和决心,分区进行分区修剪的匹配行。

此外,两RANGE COLUMNS分区和表列分区支持非整数列的使用定义值的范围或列表成员。允许的数据类型如下表所示:

讨论RANGE COLUMNS表列在接下来的两个章节划分假定你已经熟悉基于范围和列表支持MySQL 5.1及以后的划分;关于这些的更多信息,参见第22.2.1,”范围划分”,和22.2.2节,“列表分区”,分别

22.2.3.1范围列分区

范围列分区类似范围分区,但可以使用基于多个列的值范围定义分区。此外,您可以使用其他整数类型列定义范围。

RANGE COLUMNS从differs明显分解范围通过以下方式划分:

  • RANGE COLUMNS不接受的表情,只列名称。

  • RANGE COLUMNS接受一个或多个列

    RANGE COLUMNS分区之间的比较元组(列值列表)而不是之间的标量值的比较。行的位置RANGE COLUMNS分区是基于比较元组;这进一步后本节中讨论的。

  • RANGE COLUMNS分区列不限于整数列;字符串,DATEDATETIME柱也可作为分区依据列。(见第22.2.3,”栏目划分”,详情。)

创建一个表分区的基本语法RANGE COLUMNS这里展示的是:

创建表table_name通过范围分区(列column_list(partition)partition_name不太多的价值value_list)[,分区partition_name不太多的价值value_list)] […])column_listcolumn_name【,column_name] […]value_listvalue【,value] […]
笔记

不是所有的CREATE TABLE选项,可以在创建分区表如下所示。完全的信息,参见第13.1.18,“创建表的语法

在语法上面,column_list是一个或多个列(有时称为分区列列表),和value_list是一个列表中的值(即,它是一个分区定义的值列表)。在value_list必须为每个分区定义提供,每value_list必须有相同数量的值为column_list有柱。一般来说,如果你使用N列中的专栏条款,然后每个VALUES LESS THAN条款也必须提供一个清单N价值观

在分区列列表和值列表中定义的每个分区的元素必须以相同的顺序出现。此外,值列表中的每个元素必须是相同的数据类型的列的列表中的相应元素。然而,为了在分区列列表中的列的名称和值的列表,不必为表中的列定义的主要部分的顺序相同CREATE TABLE声明。partitioned as with表模式范围,你可以使用MAXVALUE代表这样一个值,任何合法的值插入一个给定的列总是小于这个值。这里是一个例子CREATE TABLE声明有助于说明所有这些点:

MySQL的&#62;CREATE TABLE rcx (-&#62;a INT,-&#62;b INT,-&#62;c CHAR(3),-&#62;d INT-&#62;)-&#62;PARTITION BY RANGE COLUMNS(a,d,c) (-&#62;PARTITION p0 VALUES LESS THAN (5,10,'ggg'),-&#62;PARTITION p1 VALUES LESS THAN (10,20,'mmm'),-&#62;PARTITION p2 VALUES LESS THAN (15,30,'sss'),-&#62;PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)-&#62;);查询行,0行受影响(0.15秒)

rcx包含列bCd。提供给分区列列表专栏3条款使用这些列,以aDc。用于定义一个分区包含相同的3个值的值列表;即每个值列表元组的形式(国际的INTchar(三)),其对应的列的数据类型aD,和c(按顺序)

行到分区布局是通过比较元组从行被插入确定相匹配的列的列表中COLUMNS用元组条款值小于子句来定义表的分区。因为我们是比较元组(即列表或设置值)而不是标量值,语义VALUES LESS THAN当利用范围列分区有所不同的情况下,简单的RANGE分区。进入范围分区,一行生成一个表达式的值等于极限值在VALUES LESS THAN永远放在相应的分区;然而,当使用范围列分区,它有时可能行的分区列列表的第一个元素是等价的,在第一个元素VALUES LESS THAN值列表放在相应的分区。

考虑RANGE该语句创建的分区表:

创建表格R1(一个int,int b)按范围分区(一)(分区P0值小于(5),分区P1值小于(次));

如果我们插入3行插入表这样的列值a对于每一行,3行存储在分区p1因为列的值是在每一种情况下不低于5,我们可以看到通过执行适当的查询INFORMATION_SCHEMA.PARTITIONS

MySQL的&#62;INSERT INTO r1 VALUES (5,10), (5,11), (5,12);查询行,3行受影响(0秒)记录:3份:0警告:0mysql &#62;SELECT PARTITION_NAME,TABLE_ROWS-&#62;FROM INFORMATION_SCHEMA.PARTITIONS-&#62;WHERE TABLE_NAME = 'r1';---------------- ------------ | partition_name | table_rows | ---------------- ------------ | P0 | 0 | | P1 |三| ---------------- ------------ 2行集(0.001秒)

Now consider similar tablerc1使用范围列与柱的划分aB中引用的COLUMNS条款,创建如下所示:

创建表的RC1(一个int,int b)的范围(A,B)列分区(分区P0值小于(5, 12),分区P3值小于(最大值,最大值));

如果我们将完全相同的行为rc1正如我们刚刚插入R1,行的分布是完全不同的:

mysql> INSERT INTO rc1 VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'rc1';
+--------------+----------------+------------+
| TABLE_SCHEMA | PARTITION_NAME | TABLE_ROWS |
+--------------+----------------+------------+
| p            | p0             |          2 |
| p            | p1             |          1 |
+--------------+----------------+------------+
2 rows in set (0.00 sec)

这是因为我们比较行而不是标量值。我们可以比较行的值插入行的限值从VALUES THAN LESS THAN用于定义分区子句P0rc1,像这样:

MySQL的&#62;SELECT (5,10) < (5,12), (5,11) < (5,12), (5,12) < (5,12);+-----------------+-----------------+-----------------+| (5,10) < (5,12) | (5,11) < (5,12) | (5,12) < (5,12) |+-----------------+-----------------+-----------------+|               1 |               1 |               0 |+-----------------+-----------------+-----------------+1 row in set (0.00 sec)

2元组(5,10)(11)评估不足(5,12),所以他们都存储在分区P0。自从5不低于5不低于12和12,(5,12)不小于(5,12),和存储在分区p1

这个SELECT在前面的示例中声明,也可以写成使用显式构造函数这样行:

SELECT ROW(5,10) < ROW(5,12), ROW(5,11) < ROW(5,12), ROW(5,12) < ROW(5,12);

关于行构造函数使用MySQL的更多信息,参见第13.2.11.5,“行子”

partitioned for a table模式RANGE COLUMNS只使用一个单一的分区列,排在分区的存储为一个等效的已分区表的相同范围。以下CREATE TABLE语句创建一个表分区范围列采用1分区列:

CREATE TABLE rx (
    a INT,
    b INT
)
PARTITION BY RANGE COLUMNS (a)  (
    PARTITION p0 VALUES LESS THAN (5),
    PARTITION p1 VALUES LESS THAN (MAXVALUE)
);

如果我们插入行(5,10)(11),和(5,12)在这个表中,我们可以看到,他们的位置是相同的表R我们创建并填充前:

mysql> INSERT INTO rx VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'rx';
+--------------+----------------+------------+
| TABLE_SCHEMA | PARTITION_NAME | TABLE_ROWS |
+--------------+----------------+------------+
| p            | p0             |          0 |
| p            | p1             |          3 |
+--------------+----------------+------------+
2 rows in set (0.00 sec)

也可以创建表分区RANGE COLUMNS在限值的一个或多个列在连续的分区定义重复。你可以这样做,只要用于定义分区列值的元组是严格递增的。例如,下面的CREATE TABLE报表是有效的:

创建表的RC2(一个int,int b)的范围(A,B)列分区(分区P0值小于(0),分区P1值小于(10,20),分区P2的值小于(10,30),分区P3值小于(最大值,最大值);创建表RC3(一)int,int)B的范围列分区(A,B)(分区P0值小于(0),分区P1值小于(10,20),分区P2的值小于(10,30),分区P3值小于(10,35),分区P4值小于(40),分区P5值小于比(MaxValue最大));

下面的语句也成功了,尽管它可能乍一看,它不会,因为限值的列b25分区P020分区p1,和限值的列C100分区p150分区P2

CREATE TABLE rc4 (
    a INT,
    b INT,
    c INT
)
PARTITION BY RANGE COLUMNS(a,b,c) (
    PARTITION p0 VALUES LESS THAN (0,25,50),
    PARTITION p1 VALUES LESS THAN (10,20,100),
    PARTITION p2 VALUES LESS THAN (10,30,50)
    PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)
 );

当表partitioned模式设计RANGE COLUMNS,你可以测试连续分割的定义,比较预期的元组使用MySQL客户端,这样:

mysql> SELECT (0,25,50) < (10,20,100), (10,20,100) < (10,30,50);
+-------------------------+--------------------------+
| (0,25,50) < (10,20,100) | (10,20,100) < (10,30,50) |
+-------------------------+--------------------------+
|                       1 |                        1 |
+-------------------------+--------------------------+
1 row in set (0.00 sec)

如果一个CREATE TABLE声明中包含不严格递增的顺序划分的定义,它没有一个错误,如本例所示:

MySQL的&#62;CREATE TABLE rcf (-&#62;a INT,-&#62;b INT,-&#62;c INT-&#62;)-&#62;PARTITION BY RANGE COLUMNS(a,b,c) (-&#62;PARTITION p0 VALUES LESS THAN (0,25,50),-&#62;PARTITION p1 VALUES LESS THAN (20,20,100),-&#62;PARTITION p2 VALUES LESS THAN (10,30,50),-&#62;PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE)-&#62;);错误1493(hy000):值小于值必须为每个分区严格递增

当你得到这样一个错误,你可以推断出的分区定义无效的小于列列表之间的比较。在这种情况下,问题是分区的定义p2因为用于定义不小于用于定义分区的元组元组P3,如下所示:

mysql> SELECT (0,25,50) < (20,20,100), (20,20,100) < (10,30,50);
+-------------------------+--------------------------+
| (0,25,50) < (20,20,100) | (20,20,100) < (10,30,50) |
+-------------------------+--------------------------+
|                       1 |                        0 |
+-------------------------+--------------------------+
1 row in set (0.00 sec)

它也可能为MAXVALUE对多个相同的列出现值小于条款时使用RANGE COLUMNS。然而,单个列的极限值在连续的分区定义应增加,应不超过一个分区定义最大作为所有列的值的上限,这个分区定义应该出现在名单上PARTITION ... VALUES LESS THAN条款.此外,您不能使用最大为限制在一个以上的分区定义的第一列的值。

如前所述,也有可能与RANGE COLUMNS分区使用非整数列作为分区列。(见第22.2.3,”栏目划分”,对于这些的完整清单。)考虑表名employees(不分区),使用下面的语句创建:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int不空,不空store_id int);

使用RANGE COLUMNS分区,您可以创建一个版本的这个表中存储的每一行四个分区的基础上,员工的姓名,这样:

创建表employees_by_lname(ID为不空,名varchar(30)、lname VARCHAR(30),雇用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int不空,不空store_id int)的范围列分区(模型)(分区P0值小于(G’),分区P1值小于(是的),分区P2的值小于(不),分区P3值小于(次));

或者,你可能会导致employees表为先前创建使用该方案通过执行下面的分区ALTER TABLE声明:

通过改变范围列雇员表分区(模型)(分区P0值小于(G’),分区P1值小于(是的),分区P2的值小于(不),分区P3值小于(次));
笔记

因为不同的字符集和排序规则有不同的排序顺序,使用的字符集和排序规则可能影响分区的分区表RANGE COLUMNS一个给定的行存储在使用字符串列作为分区列。此外,对于一个给定的数据库,表更改字符集和整理,或如表列创建后可能引起行是如何分布的。例如,使用一个敏感的整理时,&#39;和&#39;各种各样的前'Andersen',但使用的排序规则是不区分大小写的时候,倒是真的。

关于MySQL如何处理字符集和整理,看10章,字符集Unicode排序规则,

同样的,你可以使employees表被划分在这样一种方式,每行存储在一个分区的基础上在这十年中,相应的员工被雇佣的ALTER TABLE表所示:

通过范围列表(聘用)员工分区(分区P0值小于(&#39;1970-01-01 &#39;),分区P1值小于(&#39;1980-01-01 &#39;),分区P2的值小于(&#39;1990-01-01 &#39;),分区P3值小于(&#39;2000-01-01 &#39;),分区P4值小于(&#39;2010-01-01 &#39;),分区P5值小于(次));

看到第13.1.18,“创建表的语法关于更多的信息,PARTITION BY RANGE COLUMNS语法

22.2.3.2列表列分区

MySQL 8提供支持LIST COLUMNS分区。这是一个变种列表分区,使多个列作为分区键,和其他比整数类型用作分区列的数据类型的列可以使用字符串类型,DATE,和DATETIME专栏(关于允许的数据类型的更多信息专栏分区列,看第22.2.3,”栏目划分”。)

假设你有一个业务,客户已在12个城市,销售和市场营销的目的,你组织成3个城市各如下表所示的4个地区:

地区城市
奥斯卡港,h?gsby,m?nster?s
瑞典维默比,都柏林,V?stervik
n?ssj?,埃克舍?,韦特兰达
uppvidinge,阿尔沃斯塔,v?xjo

LIST COLUMNS分区,您可以创建一个客户数据,指定行任何四分区对应于基于顾客所在城市名称,这些地区表,如下所示:

CREATE TABLE customers_1 (    first_name VARCHAR(25),    last_name VARCHAR(25),    street_1 VARCHAR(30),    street_2 VARCHAR(30),    city VARCHAR(15),    renewal DATE)PARTITION BY LIST COLUMNS(city) (    PARTITION pRegion_1 VALUES IN(&#39;Oskarshamn&#39;, &#39;H?gsby&#39;, &#39;M?nster?s&#39;),    PARTITION pRegion_2 VALUES IN(&#39;Vimmerby&#39;, &#39;Hultsfred&#39;, &#39;V?stervik&#39;),    PARTITION pRegion_3 VALUES IN(&#39;N?ssj?&#39;, &#39;Eksj?&#39;, &#39;Vetlanda&#39;),    PARTITION pRegion_4 VALUES IN(&#39;Uppvidinge&#39;, &#39;Alvesta&#39;, &#39;V?xjo&#39;));

作为与分区RANGE COLUMNS,你不需要在使用表达式columns()条款将列值为整数。(事实上,比其他列的名称不允许使用与表达COLUMNS()。)

也可以使用DATEDATETIME列,如下面的例子,使用相同的名称和列为customers_1表示以前,但采用LIST COLUMNS基于分区更新列存储的行在一个四分区取决于这周在2010年2月客户的帐户计划更新:

CREATE TABLE customers_2 (
    first_name VARCHAR(25),
    last_name VARCHAR(25),
    street_1 VARCHAR(30),
    street_2 VARCHAR(30),
    city VARCHAR(15),
    renewal DATE
)
PARTITION BY LIST COLUMNS(renewal) (
    PARTITION pWeek_1 VALUES IN('2010-02-01', '2010-02-02', '2010-02-03',
        '2010-02-04', '2010-02-05', '2010-02-06', '2010-02-07'),
    PARTITION pWeek_2 VALUES IN('2010-02-08', '2010-02-09', '2010-02-10',
        '2010-02-11', '2010-02-12', '2010-02-13', '2010-02-14'),
    PARTITION pWeek_3 VALUES IN('2010-02-15', '2010-02-16', '2010-02-17',
        '2010-02-18', '2010-02-19', '2010-02-20', '2010-02-21'),
    PARTITION pWeek_4 VALUES IN('2010-02-22', '2010-02-23', '2010-02-24',
        '2010-02-25', '2010-02-26', '2010-02-27', '2010-02-28')
);

这部作品,但也能够定义和维护如果日期涉及数量增长非常大的麻烦;在这种情况下,它采用更实用的通常是RANGE范围列分区而不是。在这种情况下,我们希望使用自列作为分区键是一个DATE柱,我们使用范围列分区,如下所示:

CREATE TABLE customers_3 (
    first_name VARCHAR(25),
    last_name VARCHAR(25),
    street_1 VARCHAR(30),
    street_2 VARCHAR(30),
    city VARCHAR(15),
    renewal DATE
)
PARTITION BY RANGE COLUMNS(renewal) (
    PARTITION pWeek_1 VALUES LESS THAN('2010-02-09'),
    PARTITION pWeek_2 VALUES LESS THAN('2010-02-15'),
    PARTITION pWeek_3 VALUES LESS THAN('2010-02-22'),
    PARTITION pWeek_4 VALUES LESS THAN('2010-03-01')
);

看到第22.2.3.1,范围列分区”为更多的信息

另外(如RANGE COLUMNS分区),你可以使用多个列columns()条款.

看到第13.1.18,“创建表的语法关于更多的信息,PARTITION BY LIST COLUMNS()语法

22.2.4 hash分解

分区HASH主要用于保证预定数量的分区中的数据均匀分布。的范围或列表分区,您必须明确指定哪个分区给定列的值或者设置列值应存放在;与哈希分区,这一决定是照顾你,你只需要指定一个列值或表达式基于散列列值和分区数为分区表是可分的。

分区表的使用HASH划分,有必要追加到CREATE TABLE声明一个散列分区法(expr条款,在expr是返回一个整型表达式。这仅仅是一个列的类型的名称是一个MySQL的整数类型。此外,你可能想跟随分区num,在那里num是一个正整数表示分区的数量,桌子是可分。

笔记

为简单起见,在下面的例子中的表格不使用任何键。你应该知道,如果一个表有唯一的键,每一列用于划分表达此表必须是每一个独特的关键部分,包括主键。看到“22.6.1分解段,原钥匙,钥匙和钥匙,独特的”为更多的信息

下面的语句创建一个表,使用哈希算法对store_id柱分为4个分区:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int,int store_id)散列分区法(store_id)分区4;

如果不包括PARTITIONS条款,分区的默认数量;使用PARTITIONS关键词无数量后,结果在一个语法错误。

你也可以使用一个SQL表达式,返回一个整数expr。例如,你可能想划分这一年的员工被雇用。这可以通过如下所示:

创建员工信息表(ID为不空,名为varchar(30),lname VARCHAR(30),聘用日期不为空的默认“1970-01-01,分离的日期无效的默认9999-12-31 &#39;,job_code int,int store_id)散列分区法(年(雇))分区4;

expr必须返回一个数,随机整数(换句话说,它应该是不同的但确定性),并且必须不包含任何禁止的结构描述22.6节,“分区”的约束和限制。你也应该记住,这种表达是每次插入一行或更新的评价(或删除);这意味着非常复杂的表达式可能会导致性能问题,尤其是当执行操作(如批量插入)影响许多排在同一时间。

最高效的哈希函数是一个运行在一个单一的表列的值增加或减少持续的列的值,因为这可以修剪范围分区。这是更密切的表达与它所基于的列的值的变化,更有效地使用MySQL可以表达为哈希分区。

例如,在date_col是一列式DATE,然后表达TO_DAYS(date_col)据说与价值成正比日期,因为在每一个变化的价值date_col,在一致的方式表达的变化值。表达的差异YEAR(date_col)相对于日期不完全是那样直接TO_DAYS(date_col),因为不是每个可能的变化日期产生一个等效的变化YEAR(date_col)。即使如此,YEAR(date_col)是一个散列函数的很好的候选人,因为它直接随一部分日期有没有可能改变date_col产生不成比例的变化YEAR(date_col)

相反,假设你有一个叫作int_col其类型INT。现在考虑的表达POW(5-int_col,3) + 6。这是一个好的选择因为散列函数值的变化在_ int不保证产品在该表达式的值成比例的变化。改变的价值int_col通过一个给定的量可以产生各种不同的表达式的值的变化。例如,改变在_ int5产生一个变化的-1在该表达式的值,但变化的价值在_ int6产生一个变化的-7在表达式的值

换句话说,越密切的列的值与表达式的值图如下直线的方程追踪y=cx哪里c是某个非零常数,更好的表达是适合散列。这是因为更多的非线性表达式,该分区也容易产生数据之间的分布越不均匀。

在理论上,对于涉及多个列值表达式的修剪也是可以的,但确定的这种表达是合适的可以是相当困难和费时。为此,哈希表达涉及多个列的使用不是特别推荐。

什么时候PARTITION BY HASH是用于存储引擎确定哪个分区num分区使用基于表达式的结果的模。换句话说,对于一个给定的表达expr,其中分区存储记录号分区N,在那里N= MOD(exprnum。假设表T1定义如下,以便它有4个分区:

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;

如果你插入一条记录到t1谁的col3'2005-09-15',然后分配其存储决定如下:

MOD(YEAR('2005-09-01'),4)=  MOD(2005,4)=  1

MySQL 8还支持一个变种HASH分区被称为线性散列采用更复杂的算法来确定新的行插入到分区表的位置。看到第22.2.4.1,线性散列分区”,为描述这个算法

用户提供的表达是每一次记录的插入或更新评估。它还可以根据不同的情况进行评估,当记录被删除。

22.2.4.1线性哈希分区

MySQL也支持线性散列,它不同于常规的散列,线性散列利用线性的权力的两个算法而经常采用的哈希散列函数的值模。

在语法上,线性散列分区和普通散列的唯一区别是增加了LINEAR关键词在分区条款,如下图所示:

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,
    store_id INT
)
PARTITION BY LINEAR HASH( YEAR(hired) )
PARTITIONS 4;

给定一个表达expr,分区中存储记录时使用线性散列分区号N从中num分区,在那里N根据下面的算法推导:

  1. 找到2个大于下功率num。我们称这种价值V;它可以计算为:

    V= POWER(2, CEILING(LOG(2,num)))

    (假设num13。然后LOG(2,13)是3.7004397181411。CEILING(3.7004397181411)4,和V=POWER(2,4)16,which is)。

  2. 配置N=Fcolumn_list)和(V- 1)

  3. N>=num

    • 配置V=V/ 2

    • 配置N=N&#38;(V- 1)

假设表t1,使用线性哈希分区和具有六分区,使用该语句创建:

创建表T1(col1 int,char(五),col2 col3日期)通过线性哈希分区(分区六年(COL3));

现在假设你想插入两个记录t1具有col3列的值'2003-04-14'“1998-10-19”。对于第一个分区数目决定如下:

V = POWER(2, CEILING( LOG(2,6) )) = 8
N = YEAR('2003-04-14') & (8 - 1)
   = 2003 & 7
   = 3

(3 >= 6 is FALSE: record stored in partition #3)

数的划分在第二记录存储的计算如下所示:

V = 8
N = YEAR('1998-10-19') & (8 - 1)
  = 1998 & 7
  = 6

(6 >= 6 is TRUE: additional step required)

N = 6 & ((8 / 2) - 1)
  = 6 & 3
  = 2

(2 >= 6 is FALSE: record stored in partition #2)

在线性哈希分区的好处是增加,下降,合并,拆分分区作出更快,有利于在处理含有非常大量的数据表(百万兆字节)。缺点是数据不可能均匀分布在分区之间相比采用哈希分区分布规律。

22.2.5密钥分配

划分的关键是类似的哈希分区,除了在哈希分区使用一个自定义的表情,散列函数为重点的划分是由MySQL服务器提供。

语法规则CREATE TABLE ... PARTITION BY KEY类似于创建一个表,按哈希分区。主要的区别如下:

  • KEY而不是使用搞砸

  • KEY只需要一个列表的零个或多个列的名称。任何列作为分区键必须是表的主键的一部分或全部,如果表中有一个。在没有列名称指定为分区键,表的主键时,如果有一个。例如,下面的CREATE TABLE声明是有效的:MySQL 8.0

    创建表的K1(ID INT NOT NULL主键,名称为varchar(20))的key()分区2分区;

    如果没有主键,但有一个独特的关键,那么唯一的密钥是用于分区键:

    CREATE TABLE k1 (
        id INT NOT NULL,
        name VARCHAR(20),
        UNIQUE KEY (id)
    )
    PARTITION BY KEY()
    PARTITIONS 2;
    

    然而,如果唯一键列不被定义为NOT NULL,然后前面的语句将失败。

    在这些情况下,分区键是id柱,即使它不在输出显示SHOW CREATE TABLE或在partition_expression列的INFORMATION_SCHEMA.PARTITIONS

    不像其他的分区类型的情况下,用于分区列KEY不限于整数或无效的价值观。例如,下面的CREATE TABLE声明是有效的:

    创建表的TM1(S1 char(32)主键)分区的分区键(S1)10;

    前面的说法是有效的,是一个不同的分区类型被指定。(在这种情况下,简单的使用PARTITION BY KEY()也将是有效的和有相同的效果分区键(S1)村,自s1为表的主键。)

    有关此问题的更多信息,参见22.6节,“分区”的约束和限制

    重要

    一个关键的分区表,你不能执行ALTER TABLE DROP PRIMARY KEY,因为这样做产生的误差错误1466(hy000):在分区函数中没有找到表字段列表的字段

也可以通过线性关键分区表。这里是一个简单的例子:

CREATE TABLE tk (
    col1 INT NOT NULL,
    col2 CHAR(5),
    col3 DATE
)
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;

这个LINEAR关键词具有相同的效果钥匙分割它HASH分区的分区号,使用权两算法而不是模算术推导。看到第22.2.4.1,线性散列分区”,为描述这个算法及其启示。

22.2.6分区

分区也被称为复合分区-在一个分区表的每个分区的进一步划分。考虑以下CREATE TABLE声明:

创建表的TS(ID int,购买日期)按范围分区(年(购买))子分区哈希(to_days(购买)2)子分区(分区P0值小于(1990),分区P1值小于(2000),分区P2值小于最大值);

ts有3个范围走吧这些部分的每一部分p0P1,和p2-进一步分为2个子。实际上,整个表分3 * 2 = 6走吧但是,由于我们的行动PARTITION BY RANGE条款,前2个店只有那些记录一个值小于1990的购买专栏

这是可能的,分区的子分区表RANGE列表。。。。。。。subpartitions可能使用。HASH钥匙分区。这也被称为复合分区

笔记

SUBPARTITION BY HASH集群化的关键一般遵循相同的语法规则PARTITION BY HASH分区键,分别。这是一个例外,SUBPARTITION BY KEY(不像分区键)目前不支持默认的列,所以用于这一目的的列必须是指定的,即使有一个明确的主键的表。这是一个已知的问题,我们正在努力解决;看与分区的问题,更多的信息和例子

它也可以定义不会显式使用SUBPARTITION子句指定单个的子分区选项。例如,一个更复杂的方式创建相同的表TS如前一个例子所示将:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE( YEAR(purchased) )
    SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
        PARTITION p0 VALUES LESS THAN (1990) (
            SUBPARTITION s0,
            SUBPARTITION s1
        ),
        PARTITION p1 VALUES LESS THAN (2000) (
            SUBPARTITION s2,
            SUBPARTITION s3
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE (
            SUBPARTITION s4,
            SUBPARTITION s5
        )
    );

注意一些语法项目如下:

  • each have the same partition number of subpartitions必备。

  • 如果你明确地定义任何不会使用SUBPARTITION在任何分区的分区表,你必须定义他们。换句话说,下面的语句将失败:

    创建表的TS(ID int,购买日期)按范围分区(年(购买))子分区哈希(to_days(购买)(分区)P0值小于(1990)(子子S0,S1),分区P1值小于(2000),分区P2值小于最大值(子分区S2,子分区S3));

    这句话也用不SUBPARTITIONS 2

  • 每个SUBPARTITION条款必须包括(至少)的子分区的名称。否则,你可以设置所需的选项的子分区或让它承担其违约,选项设置。

  • 子分区的名称必须在整个表中是唯一的。例如,下面的CREATE TABLE声明是有效的:

    创建表的TS(ID int,购买日期)按范围分区(年(购买))子分区哈希(to_days(购买)(分区)P0值小于(1990)(子子S0,S1),分区P1值小于(2000)(S2 S3子,子分区,分区P2的值)小于最大值(子子S4、S5));

22.2.7 MySQL如何分割处理空

分区在MySQL不允许NULL作为一个分区表达式的值,它是否是一个列值或用户提供的表达式的值。即使是允许使用无效的作为一个表达式,否则必须产生一个整数的值,记住这一点是重要的NULL是不是一个数字。MySQL的分区实施治疗无效的是比任何非—NULL价值,正如顺序做.

这意味着治疗NULL不同类型的分区之间的变化,以及可能产生的行为,你不如果你不准备期待。在这种情况下,我们在本节讨论如何处理MySQL分区类型无效的确定在这一行应该存放的分区时的价值,并提供例子每。

处理空与范围划分如果你插入一行到一个表分区RANGE这样,用来确定分区列的值无效的,行插入到最低的分区。数据库中名为考虑一下这两个表p,创建如下:

MySQL的&#62;CREATE TABLE t1 (-&#62;c1 INT,-&#62;c2 VARCHAR(20)-&#62;)-&#62;PARTITION BY RANGE(c1) (-&#62;PARTITION p0 VALUES LESS THAN (0),-&#62;PARTITION p1 VALUES LESS THAN (10),-&#62;PARTITION p2 VALUES LESS THAN MAXVALUE-&#62;);查询行,0行受影响(0.09秒)MySQL &#62;CREATE TABLE t2 (-&#62;c1 INT,-&#62;c2 VARCHAR(20)-&#62;)-&#62;PARTITION BY RANGE(c1) (-&#62;PARTITION p0 VALUES LESS THAN (-5),-&#62;PARTITION p1 VALUES LESS THAN (0),-&#62;PARTITION p2 VALUES LESS THAN (10),-&#62;PARTITION p3 VALUES LESS THAN MAXVALUE-&#62;);查询行,0行受影响(0.09秒)

你可以看到创建的分区,这两CREATE TABLE使用下面的查询语句PARTITIONS表中information_schema数据库:

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH
     >   FROM INFORMATION_SCHEMA.PARTITIONS
     >   WHERE TABLE_SCHEMA = 'p' AND TABLE_NAME LIKE 't_';
+------------+----------------+------------+----------------+-------------+
| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |
+------------+----------------+------------+----------------+-------------+
| t1         | p0             |          0 |              0 |           0 |
| t1         | p1             |          0 |              0 |           0 |
| t1         | p2             |          0 |              0 |           0 |
| t2         | p0             |          0 |              0 |           0 |
| t2         | p1             |          0 |              0 |           0 |
| t2         | p2             |          0 |              0 |           0 |
| t2         | p3             |          0 |              0 |           0 |
+------------+----------------+------------+----------------+-------------+
7 rows in set (0.00 sec)

(有关此表的更多信息见24.14节,“information_schema分区表”。)现在让我们填充这些表包含一个单排NULL在列作为分区键,并验证该行被插入使用一对SELECT声明:

MySQL的&#62;INSERT INTO t1 VALUES (NULL, 'mothra');查询行,1行的影响(0秒)MySQL &#62;INSERT INTO t2 VALUES (NULL, 'mothra');查询行,1行的影响(0秒)MySQL &#62;SELECT * FROM t1;------ -------- | ID |名字| ------ -------- |空| Mothra | ------ -------- 1行集(0秒)MySQL &#62;SELECT * FROM t2;第二次会议(第三次会议)

你可以看到,采用分区通过重新运行以前的查询与存储插入行INFORMATION_SCHEMA.PARTITIONS检查输出:

MySQL的&#62;SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH&#62;FROM INFORMATION_SCHEMA.PARTITIONS&#62;WHERE TABLE_SCHEMA = 'p' AND TABLE_NAME LIKE 't_';------------ ---------------- ------------ ---------------- ------------- | table_name | partition_name | table_rows | avg_row_length | data_length | ------------ ---------------- ------------ ---------------- -------------| T1 | P0 | 1 | 20 | 20 || T1 | | P1 0 0 0 | | | | T1 | | P2 0 0 0 | | || T2 | P0 | 1 | 20 | 20 || T2 | | P1 0 0 0 | | | | T2 | | P2 0 0 0 | | | | T2 | | P3 0 0 0 | | | ------------ ---------------- ------------ ---------------- ------------- 7 rows在设定(0.01秒)

你也可以证明这些行删除这些分区存储在最低编号的分区的每个表,然后重新运行SELECT声明:

MySQL的&#62;ALTER TABLE t1 DROP PARTITION p0;查询行,0行受影响(0.16秒)MySQL &#62;ALTER TABLE t2 DROP PARTITION p0;查询行,0行受影响(0.16秒)MySQL &#62;SELECT * FROM t1;空集合(0秒)MySQL &#62;SELECT * FROM t2;空集(0.001秒)

(更多信息ALTER TABLE ... DROP PARTITION,看到第13.1.8,“ALTER TABLE语法”。)

NULL也以这种方式处理的分区,使用SQL函数的表达式。假设我们定义一个表使用CREATE TABLE如这一声明:

创建表tndate(ID int,DT日期)按范围分区(年(DT))(分区P0值小于(1990年),分区P1值小于(2000年),分区P2值小于最大值);

与其他MySQL功能,YEAR(NULL)退货无效的。一行dt列值无效的作为虽然分区表达式的值小于其他任何值,所以插入分区p0

处理空列表分区已分区表的LIST承认无效的值,当且仅当它的一个分区是使用包含定义的值列表NULL。反之,一个表分区列表不明确使用NULL值列表中的拒绝导致行无效的对于分区表达式的值,如图所示:

mysql> CREATE TABLE ts1 (
    ->     c1 INT,
    ->     c2 VARCHAR(20)
    -> )
    -> PARTITION BY LIST(c1) (
    ->     PARTITION p0 VALUES IN (0, 3, 6),
    ->     PARTITION p1 VALUES IN (1, 4, 7),
    ->     PARTITION p2 VALUES IN (2, 5, 8)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO ts1 VALUES (9, 'mothra');
ERROR 1504 (HY000): Table has no partition for value 9

mysql> INSERT INTO ts1 VALUES (NULL, 'mothra');
ERROR 1504 (HY000): Table has no partition for value NULL

只有行具有c1价值之间8包括可插入TS1NULL超出这个范围,就像数。我们可以创建表ts2TS3在值列表包含NULL,如下所示:

MySQL的&#62;CREATE TABLE ts2 (-&#62;c1 INT,-&#62;c2 VARCHAR(20)-&#62;)-&#62;PARTITION BY LIST(c1) (-&#62;PARTITION p0 VALUES IN (0, 3, 6),-&#62;PARTITION p1 VALUES IN (1, 4, 7),-&#62;PARTITION p2 VALUES IN (2, 5, 8),-&#62;PARTITION p3 VALUES IN (NULL)-&#62;);查询好,为受影响的行(0.01秒)MySQL &#62;CREATE TABLE ts3 (-&#62;c1 INT,-&#62;c2 VARCHAR(20)-&#62;)-&#62;PARTITION BY LIST(c1) (-&#62;PARTITION p0 VALUES IN (0, 3, 6),-&#62;PARTITION p1 VALUES IN (1, 4, 7, NULL),-&#62;PARTITION p2 VALUES IN (2, 5, 8)-&#62;);查询好,为受影响的行(0.01秒)

定义分区值列表时,你可以(也应该)治疗NULL就像任何其他的价值。例如,两值(null)VALUES IN (1, 4, 7, NULL)是有效的,如(null值在1,4,7)VALUES IN (NULL, 1, 4, 7),等等。你可以插入一行无效的c1为每个表TS2ts3

MySQL的&#62;INSERT INTO ts2 VALUES (NULL, 'mothra');查询行,1行的影响(0秒)MySQL &#62;INSERT INTO ts3 VALUES (NULL, 'mothra');查询行,1行的影响(0秒)

通过发行相应的查询INFORMATION_SCHEMA.PARTITIONS,你可以确定哪些分区用来存放刚才插入的行(我们假设,在前面的例子中,这个分区表中创建P数据库):

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH
     >   FROM INFORMATION_SCHEMA.PARTITIONS
     >   WHERE TABLE_SCHEMA = 'p' AND TABLE_NAME LIKE 'ts_';
+------------+----------------+------------+----------------+-------------+
| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |
+------------+----------------+------------+----------------+-------------+
| ts2        | p0             |          0 |              0 |           0 |
| ts2        | p1             |          0 |              0 |           0 |
| ts2        | p2             |          0 |              0 |           0 |
| ts2        | p3             |          1 |             20 |          20 |
| ts3        | p0             |          0 |              0 |           0 |
| ts3        | p1             |          1 |             20 |          20 |
| ts3        | p2             |          0 |              0 |           0 |
+------------+----------------+------------+----------------+-------------+
7 rows in set (0.01 sec)

如本节前面,你也可以验证分区是用于存储行删除这些分区,然后执行SELECT

空哈希分区处理的关键。NULL是分区表的不同处理搞砸KEY。在这种情况下,任何分区表达式无效的值作为返回值为零,但其。我们可以通过在创建一个表的分区的文件系统的影响,验证了这种行为HASH和填充它与记录包含适当的值。假设你有一个表TH(也在p使用下面的语句创建数据库):

MySQL的&#62;CREATE TABLE th (-&#62;c1 INT,-&#62;c2 VARCHAR(20)-&#62;)-&#62;PARTITION BY HASH(c1)-&#62;PARTITIONS 2;查询行,0行受影响(0秒)

分区属于这个表格可以被用在这里显示的查询:

mysql> SELECT TABLE_NAME,PARTITION_NAME,TABLE_ROWS,AVG_ROW_LENGTH,DATA_LENGTH
     >   FROM INFORMATION_SCHEMA.PARTITIONS
     >   WHERE TABLE_SCHEMA = 'p' AND TABLE_NAME ='th';
+------------+----------------+------------+----------------+-------------+
| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |
+------------+----------------+------------+----------------+-------------+
| th         | p0             |          0 |              0 |           0 |
| th         | p1             |          0 |              0 |           0 |
+------------+----------------+------------+----------------+-------------+
2 rows in set (0.00 sec)

TABLE_ROWS每个分区0。现在插入两排成TH谁的c1列的值无效的0,确认这些行被插入,如图所示:

mysql> INSERT INTO th VALUES (NULL, 'mothra'), (0, 'gigan');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM th;
+------+---------+
| c1   | c2      |
+------+---------+
| NULL | mothra  |
+------+---------+
|    0 | gigan   |
+------+---------+
2 rows in set (0.01 sec)

回想一下,对于任意整数N,价值零模N总是无效的。partitioned by that are for表HASH钥匙,这个结果是确定正确的分区处理0。检查INFORMATION_SCHEMA.PARTITIONS表一次又一次,我们可以看到,一排排被插入到分区P0

mysql> SELECT TABLE_NAME, PARTITION_NAME, TABLE_ROWS, AVG_ROW_LENGTH, DATA_LENGTH
     >   FROM INFORMATION_SCHEMA.PARTITIONS
     >   WHERE TABLE_SCHEMA = 'p' AND TABLE_NAME ='th';
+------------+----------------+------------+----------------+-------------+
| TABLE_NAME | PARTITION_NAME | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH |
+------------+----------------+------------+----------------+-------------+
| th         | p0             |          2 |             20 |          20 |
| th         | p1             |          0 |              0 |           0 |
+------------+----------------+------------+----------------+-------------+
2 rows in set (0.00 sec)

通过重复最后一个示例使用PARTITION BY KEY在的地方散列分区法在表的定义,您可以验证NULL也像对待0这种类型的划分。

22.3分区管理

有一些使用SQL语句修改分区表的方式;它可以添加,下降,重新定义,合并,或拆分现有的分区的分区使用的扩展ALTER TABLE声明。也有获取分区表和分区信息的方式。我们讨论这些问题在后面的章节中。

笔记

所有分区的分区表必须有相同数量的子分区;这是不可能的,一旦表已创建的分区的变化。

改变一个表的分区方案,只需使用ALTER TABLE声明一个partition_options选择,具有相同的语法,使用CREATE TABLE创建一个分区表;此选项(也)始于关键词分区。假设以下CREATE TABLE语句用于创建一个表,按范围分区:

创建表TRB3(ID int,NAME varchar(50),购买日期)按范围分区(年(购买)(分区)P0值小于(1990),分区P1值小于(1995),分区P2的值小于(2000),分区P3值小于(2005));

这张桌子,重新划分为两个分区使用的关键id列值为重点的基础上,你可以用这句话:

重点修改表TRB3分区(ID)分区2;

这对该表的结构相同的效果下降表并重新创建它使用CREATE TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2;

ALTER TABLE ... ENGINE = ...仅仅改变存储引擎的表,叶表的分区方案完整。声明成功只有在目标存储引擎提供的分区支持。你可以使用修改表…删除分区删除一个表的分区;看第13.1.8,“ALTER TABLE语法”

重要

只有一个PARTITION BY添加分区DROP PARTITIONreorganize partition,或COALESCE PARTITION条款可用于在一个给定的ALTER TABLE声明。如果你(例如)希望减少分区和重组表剩余的分区,你必须在两个独立的这样做ALTER TABLE(一个使用报表删除分区然后一次使用REORGANIZE PARTITION

你可以删除所有行的一个或多个选定的分区使用ALTER TABLE ... TRUNCATE PARTITION

22.3.1管理范围和列表分区

添加范围和列表分区滴以类似的方式处理,所以我们讨论在本节划分这两类管理。有关用表,哈希分区工作或关键信息,看第22.3.2,“管理散列分区”

a partition from table落水partitioned by that is或者RANGE或由列表可以通过使用ALTER TABLE声明与删除分区选项假设你已经创建了一个表,按范围分区,然后填入10记录使用以下CREATE TABLEINSERT声明:

MySQL的&#62;CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)-&#62;PARTITION BY RANGE( YEAR(purchased) ) (-&#62;PARTITION p0 VALUES LESS THAN (1990),-&#62;PARTITION p1 VALUES LESS THAN (1995),-&#62;PARTITION p2 VALUES LESS THAN (2000),-&#62;PARTITION p3 VALUES LESS THAN (2005),-&#62;PARTITION p4 VALUES LESS THAN (2010),-&#62;PARTITION p5 VALUES LESS THAN (2015)-&#62;);查询行,0行受影响(0.28秒)MySQL &#62;INSERT INTO tr VALUES-&#62;(1, 'desk organiser', '2003-10-15'),-&#62;(2, 'alarm clock', '1997-11-05'),-&#62;(3, 'chair', '2009-03-10'),-&#62;(4, 'bookcase', '1989-01-10'),-&#62;(5, 'exercise bike', '2014-05-09'),-&#62;(6, 'sofa', '1987-06-05'),-&#62;(7, 'espresso maker', '2011-11-22'),-&#62;(8, 'aquarium', '1992-08-04'),-&#62;(9, 'study desk', '2006-09-16'),-&#62;(10, 'lava lamp', '1998-12-25');查询行,10行受影响(0.05秒)记录:10份:0警告:0

你可以看到哪些项目应该被插入到分区p2如图所示:

MySQL的&#62;SELECT * FROM tr-&#62;WHERE purchased BETWEEN '1995-01-01' AND '1999-12-31';------ ------------- ------------ | ID |名字|购买| ------ ------------- ------------ | 2 |闹钟| 1997-11-05 | | 10 |熔岩灯| 1998-12-25 | ------ ------------- ------------ 2行集(0秒)

你也可以使用分区选择得到这个信息,如下所示:

mysql> SELECT * FROM tr PARTITION (p2);
+------+-------------+------------+
| id   | name        | purchased  |
+------+-------------+------------+
|    2 | alarm clock | 1997-11-05 |
|   10 | lava lamp   | 1998-12-25 |
+------+-------------+------------+
2 rows in set (0.00 sec)

看到第22,“分区选择”为更多的信息

把分区命名p2,执行以下命令:

MySQL的&#62;ALTER TABLE tr DROP PARTITION p2;查询好,为受影响的行(0秒)
笔记

这个NDBCLUSTER存储引擎不支持修改表…删除分区。它,然而,支持其他相关的扩展分区ALTER TABLE本章中所描述的

它是要记住很重要,当你删除一个分区,你也删除所有的数据被存储在该分区。你可以看到,这是通过重新运行以前的案例SELECTPERERY:

MySQL的&#62;SELECT * FROM tr WHERE purchased-&#62;BETWEEN '1995-01-01' AND '1999-12-31';空集(0.001秒)
笔记

DROP PARTITION由本地分区到位的API支持,可以使用ALGORITHM={COPY|INPLACE}DROP PARTITIONALGORITHM=INPLACE删除存储在分区的分区数据,滴。然而,DROP PARTITIONALGORITHM=COPYold_alter_table=ON重建分区表和试图将数据从下降到另一个分区的分区与兼容分区…价值观定义不能移动到另一个分区的数据将被删除。

因此,你必须有DROP一个表的权限才能执行修改表…删除分区在那张桌子上

如果你想删除所有数据,同时保留所有分区表定义和划分方案,使用TRUNCATE TABLE声明。(见第13.1.34”truncate table语法”。)

如果你想改变一个表的分区没有丢失数据,使用ALTER TABLE ... REORGANIZE PARTITION相反。看下面或第13.1.8,“ALTER TABLE语法”,有关REORGANIZE PARTITION

如果你现在执行SHOW CREATE TABLE声明中,你可以看到分区表结构已经改变:

MySQL的&#62;SHOW CREATE TABLE tr\G*************************** 1. row ***************************       Table: trCreate Table: CREATE TABLE `tr` (  `id` int(11) DEFAULT NULL,  `name` varchar(50) DEFAULT NULL,  `purchased` date DEFAULT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1/*!50100 PARTITION BY RANGE ( YEAR(purchased))(PARTITION p0 VALUES LESS THAN (1990) ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB, PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB, PARTITION p4 VALUES LESS THAN (2010) ENGINE = InnoDB, PARTITION p5 VALUES LESS THAN (2015) ENGINE = InnoDB) */1 row in set (0.00 sec)

当你插入新的行为变化表purchased列值之间“1995-01-01”'2004-12-31'包容,那些行将存储在分区P3。你可以验证这个如下:

mysql> INSERT INTO tr VALUES (11, 'pencil holder', '1995-07-12');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tr WHERE purchased
    -> BETWEEN '1995-01-01' AND '2004-12-31';
+------+----------------+------------+
| id   | name           | purchased  |
+------+----------------+------------+
|    1 | desk organiser | 2003-10-15 |
|   11 | pencil holder  | 1995-07-12 |
+------+----------------+------------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE tr DROP PARTITION p3;
Query OK, 0 rows affected (0.03 sec)

mysql> SELECT * FROM tr WHERE purchased
    -> BETWEEN '1995-01-01' AND '2004-12-31';
Empty set (0.00 sec)

行数从表中删除的结果ALTER TABLE ... DROP PARTITION不报告的服务器会用等效DELETE查询

滴水LIST从相同的角度出发修改表…删除分区语法用于坠RANGE分区。然而,有一个重要的分歧的影响,这对您使用本表之后:你不能再插入表中的任何行有任何被列入名单的价值定义删除分区的值。(见22.2.2节,“列表分区”,即为一例。)

添加一个新的范围或列表分区以前的分区表,使用ALTER TABLE ... ADD PARTITION声明。为表分区的范围,这可以用来添加一个新的范围,对现有的分区列表的末尾。假设你有一个分区表为您的组织含会员资料,它的定义如下:

CREATE TABLE members (
    id INT,
    fname VARCHAR(25),
    lname VARCHAR(25),
    dob DATE
)
PARTITION BY RANGE( YEAR(dob) ) (
    PARTITION p0 VALUES LESS THAN (1980),
    PARTITION p1 VALUES LESS THAN (1990),
    PARTITION p2 VALUES LESS THAN (2000)
);

进一步假设为成员的最低年龄是16岁。当日历的方法,2015年底,你意识到你将很快被承认的成员谁出生在2000(及以后)。你可以修改members表以容纳新成员出生在年2000至2010如下所示:

修改表的成员添加分区(分区P3值小于(2010));

表是按范围分区,您可以使用ADD PARTITION添加新的分区,分区的高端列表。试图添加在现有的分区之间或导致错误如下所示的一个新的分区,以这种方式:

MySQL的&#62;ALTER TABLE members&#62;ADD PARTITION (&#62;PARTITION n VALUES LESS THAN (1970));错误1463(hy000):值小于值必须严格?每个分区的增加

你可以解决这个问题,第一个分区为两个新的分裂,它们之间的范围,像这样:

ALTER TABLE members
    REORGANIZE PARTITION p0 INTO (
        PARTITION n0 VALUES LESS THAN (1970),
        PARTITION n1 VALUES LESS THAN (1980)
);

使用SHOW CREATE TABLE你可以看到,修改表声明已经达到期望的效果:

mysql> SHOW CREATE TABLE members\G
*************************** 1. row ***************************
       Table: members
Create Table: CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) DEFAULT NULL,
  `lname` varchar(25) DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE ( YEAR(dob))
(PARTITION n0 VALUES LESS THAN (1970) ENGINE = InnoDB,
 PARTITION n1 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2010) ENGINE = InnoDB) */
1 row in set (0.00 sec)

参见第13.1.8.1,“修改表分区操作”

你也可以使用ALTER TABLE ... ADD PARTITION添加新的分区表,分区的列表。假设一个表tt使用以下定义CREATE TABLE声明:

TT(create table id的数据,国际城市战略)分区(partition(数据)的P值(5,10,15),P1值的分区(6,12,18);

你可以在其中添加一个新分区存储行有data列的值14,和二十一如图所示:

ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21));

记住你不能添加一个新的LIST分区包含任何值,都已经包含在现有分区的值列表。如果你试图这样做,将导致一个错误:

MySQL的&#62;ALTER TABLE tt ADD PARTITION &#62;(PARTITION np VALUES IN (4, 8, 12));错误1465(hy000):多个定义在相同?列表分区

因为在任何行data列值十二已分配的分区p1,你不能创建一个新的分区表TT这包括12在值列表。要做到这一点,你可以把P1,并添加np然后一个新的P1用改性的定义。然而,正如前面所讨论的,这会导致所有数据存储在损失p1-这是通常情况下,这是不是你真正想做的事情。另一个解决方案可能会出现与新的分区表的副本进行复制数据到使用CREATE TABLE ... SELECT ...,然后把旧桌子和重命名新的,但是这可能是非常耗时,在处理大量数据。这也可能不在高可用性要求的情况下是可行的。

你可以在一个单一的添加多个分区ALTER TABLE ... ADD PARTITION声明如下所示:

创建员工信息表(ID为不空,名为varchar(50)不为空,varchar(50)模型不空,雇用日期不为空)按范围分区(年(雇))(分区P1值小于(1991),分区P2的值小于(1996),分区P3值小于(2001)、分区P4值小于(2005));改变表员工添加分区(分区P5值小于(2010),分区P6值小于最大值);

幸运的是,MySQL的实现提供了重新划分分区无数据丢失的方法。让我们先看几个简单的例子RANGE分区。回忆会员表现定义如下所示:

mysql> SHOW CREATE TABLE members\G
*************************** 1. row ***************************
       Table: members
Create Table: CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) DEFAULT NULL,
  `lname` varchar(25) DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE ( YEAR(dob))
(PARTITION n0 VALUES LESS THAN (1970) ENGINE = InnoDB,
 PARTITION n1 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2010) ENGINE = InnoDB) */
1 row in set (0.00 sec)

假设你想将所有成员行代表出生前1960到一个单独的分区。正如我们已经看到的,不能使用ALTER TABLE ... ADD PARTITION。然而,你可以使用另一个分区相关的扩展ALTER TABLE要做到这一:

修改表的成员重新分区(分区N0为S0值小于(1960),分区S1值小于(1970));

实际上,这个命令将分区p0为两个新的分区S0s1。它也将被存储在数据P0根据主要体现在两个规则到新的分区PARTITION ... VALUES ...条款,使S0只包含那些记录,YEAR(dob)小于1960,S1包含在这些行YEAR(dob)大于或等于1960但小于1970。

REORGANIZE PARTITION条款也可用于合并相邻的分区。你可以反在前面陈述的影响会员表如下所示:

ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO (
    PARTITION p0 VALUES LESS THAN (1970)
);

没有数据丢失在分裂或合并的分区使用REORGANIZE PARTITION。在执行上面的语句,mysql的动作都被存储在分区的记录S0s1为分区P0

对于一般的语法是REORGANIZE PARTITION这里展示的是:

修改表tbl_namereorganize partitionpartition_list为(partition_definitions);

在这里,tbl_name是分区表的名称,和partition_list是一个以逗号分隔的一个或多个现有的分区被改变名称列表。partition_definitions是一个逗号分隔的新的分区定义列表,它遵循相同的规则为partition_definitions列表中使用CREATE TABLE。你不限于合并成一个或几个分区,一个分区分裂成许多,使用时reorganize partition。例如,你可以整理所有四个分区的members表格一分为二,像这样:

修改表的成员重新划分P0,P1,P2,P3(划分为M0值小于(1980),分区M1值小于(2000));

你也可以使用REORGANIZE PARTITION与表分区的列表。我们再添加一个新的分区列表分区的问题tt因为新的分区表和失败有价值,已经在一个现有的分区的值列表。我们可以通过添加一个分区只包含不冲突的值处理,然后将新的分区和现有的一个,这是存储在现有的价值现在是新搬来的人:

改变表格添加分区(分区NP值(4,8));改变表格整理划分为P1,NP(分区P1值(6、18),分区NP值(4、8、12));

这里是要牢记使用时的一些关键点ALTER TABLE ... REORGANIZE PARTITIONpartitioned that are to repartition表模式范围LIST

  • 这个PARTITION用于确定新的分区方案的选择是受相同的规则与使用CREATE TABLE声明

    一个新的RANGE分区方案不能有任何重叠的范围;新列表分区方案不能有任何重叠的数据集。

  • 在分区的组合partition_definitions清单应占相同的范围或值的集合的整体组合分区命名的partition_list

    例如,分区p1P21980通过1999年一起盖在members表作为一个例子,这段。任何重组这两个分区应该覆盖相同的范围里的整体。

  • for表partitioned byRANGE你可以重组,只有相邻的隔墙;你不能跳过范围分区。

    例如,你不能重组的例子members使用一个语句从表邮袋成员reorganize partition table P0、P2 into…因为p01970年前覆盖P2从1990到1999的包容性来,所以这些不相邻的分区。(你不能跳过分区p1在这种情况下。)

  • 你不能使用REORGANIZE PARTITION要更改类型分区的表使用;例如,你无法改变范围分区HASH分区或反向。你也不能用这句话来改变分区的表达或柱。为了完成这些任务而不删除并重新创建表,您可以使用ALTER TABLE ... PARTITION BY ...,如下所示:

    通过哈希表成员分区(分区8年(DOB));

22.3.2哈希分区管理和重点

表格是由哈希或关键的划分非常相似,另一方面在一个分区设置的变化,以及不同数量的已分区表的范围或列表方式。为此,本节讨论的重点是通过哈希或分区表的修改。用于添加和表的范围或列表分区的分区滴讨论,看第22.3.1,”管理的范围和列表分区”

你不能删除分区表,分区HASH钥匙以同样的方式,你可以从表分区的RANGE列表。然而,你可以合并HASH钥匙分区使用ALTER TABLE ... COALESCE PARTITION。假设一个客户数据表包含客户分为十二分区,创建如下所示:

CREATE TABLE clients (
    id INT,
    fname VARCHAR(30),
    lname VARCHAR(30),
    signed DATE
)
PARTITION BY HASH( MONTH(signed) )
PARTITIONS 12;

减少分区的数量从12到8,执行以下ALTER TABLE声明:

MySQL的&#62;ALTER TABLE clients COALESCE PARTITION 4;查询行,0行受影响(0.02秒)

COALESCE同样适用于表分区的搞砸KEY线性散列,或LINEAR KEY。这里有一个例子与前一个类似,只是在不同的表分区的线性键

mysql> CREATE TABLE clients_lk (
    ->     id INT,
    ->     fname VARCHAR(30),
    ->     lname VARCHAR(30),
    ->     signed DATE
    -> )
    -> PARTITION BY LINEAR KEY(signed)
    -> PARTITIONS 12;
Query OK, 0 rows affected (0.03 sec)

mysql> ALTER TABLE clients_lk COALESCE PARTITION 4;
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

following the numberCOALESCE PARTITION是合并,换句话说,在其余分区的数量,这是从表中删除分区的数量。

试图删除多个分区比在一个错误的这样的结果:

mysql> ALTER TABLE clients COALESCE PARTITION 18;
ERROR 1478 (HY000): Cannot remove all partitions, use DROP TABLE instead

为增加分区数clients从12到18台,使用修改表…添加分区如图所示:

ALTER TABLE clients ADD PARTITION PARTITIONS 6;

22.3.3交换分区和子分区表

在MySQL 8中,它是可以用表使用表分区或子分区交换ALTER TABLE pt EXCHANGE PARTITION p WITH TABLE nt,在那里pt是分区表和p是分区和子分区的pt有未分区的表交换nt,提供下列陈述是真的:

  1. ntpartitioned is not本身。

  2. nt是不是一个临时表

  3. 表的结构ptnt是identical otherwise。

  4. nt不包含外键引用,并没有其他的表有任何外键引用NT

  5. 没有行nt不在的分区定义的界限p。这种情况不适用没有验证使用

除了对ALTERINSERT,和CREATE特权通常需要ALTER TABLE报表,您必须DROP特权执行ALTER TABLE ... EXCHANGE PARTITION

你也应该注意以下影响ALTER TABLE ... EXCHANGE PARTITION

  • 执行ALTER TABLE ... EXCHANGE PARTITION不调用任何分区表任何触发或表进行交换。

  • 任何AUTO_INCREMENT在交换表列被重置

  • 这个IGNORE关键词有没有效果时,使用修改表…交换分区

语法ALTER TABLE ... EXCHANGE PARTITION这里展示的是,在ptpartitioned is the table,p是分区(或子分区)进行交换,并nt是交换与非分区表p

修改表pt交换分区pnt

或者,你可以添加WITH VALIDATION没有验证。什么时候WITHOUT VALIDATION指定的ALTER TABLE ... EXCHANGE PARTITION操作不执行任何排排验证当交换分区无分区表,允许数据库管理员承担确保行内的分区定义边界的责任。与验证是默认的

有且只有一个分区或子分区可能是唯一的非分区表在一个单一的交换ALTER TABLE EXCHANGE PARTITION声明。交换多个分区或子分区,使用多个ALTER TABLE EXCHANGE PARTITION声明.交换分区不得与其他ALTER TABLE选项分区及(如适用)分区的分区表可以是任何类型或类型在MySQL 8的支持。

与非分区表交换分区

假设一个分区表e已创建并填充使用下面的SQL语句:

E(create table id不空,fname varchar(30),lname varchar(30)的城市范围分区(partition(ID),P值小于(50),P1值小于分区(partition),P2的值小于(150分),P3值小于(MaxValue))插入到;E值(1669年,“吉姆”,“史密斯”(337),“玛丽”,“琼斯”(16),“弗兰克”、“白”(2005年),“琳达”,“黑”);

现在我们创建在已分区copy ofe命名E2。这可以使用MySQL客户如下图所示:

mysql> CREATE TABLE e2 LIKE e;
Query OK, 0 rows affected (0.04 sec)

mysql> ALTER TABLE e2 REMOVE PARTITIONING;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

你可以看到它的分区表e包含行通过查询INFORMATION_SCHEMA.PARTITIONS表,这样:

MySQL的&#62;SELECT PARTITION_NAME, TABLE_ROWSFROM INFORMATION_SCHEMA.PARTITIONSWHERE TABLE_NAME = 'e';---------------- ------------ | partition_name | table_rows | ---------------- ------------ | P0 | 1 | | P1 | 0 | | P2 | 0 | | P3 | 3 | ---------------- ------------ 2行集(0秒)
笔记

对于分区InnoDB表中给出的行数table_rows列的INFORMATION_SCHEMA.PARTITIONS表只是一个估计值中使用SQL语句的优化,而不是总是准确的。

交换分区p0Ee2,你可以使用ALTER TABLE,如下所示:

MySQL的&#62;ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2;查询行,0行受影响(0.04秒)

更确切地说,只是发表的声明使分区中发现任何行是与那些在桌上发现了。你可以看到这是怎么发生的通过查询INFORMATION_SCHEMA.PARTITIONS表,如前。表行,以前发现的分区P0不再存在:

mysql> SELECT PARTITION_NAME, TABLE_ROWS
           FROM INFORMATION_SCHEMA.PARTITIONS
           WHERE TABLE_NAME = 'e';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          0 |
| p1             |          0 |
| p2             |          0 |
| p3             |          3 |
+----------------+------------+
4 rows in set (0.00 sec)

如果你查询表e2,你可以看到丢失的行现在可以发现:

mysql> SELECT * FROM e2;
+----+-------+-------+
| id | fname | lname |
+----+-------+-------+
| 16 | Frank | White |
+----+-------+-------+
1 row in set (0.00 sec)

表与分区交换不一定是空的。为了证明这一点,我们首先将新行插入表e,确保该行存储在分区P0通过选择一个id列的值小于50,验证这后来通过查询PARTITIONS

MySQL的&#62;INSERT INTO e VALUES (41, "Michael", "Green");查询行,一行受到影响(0秒)MySQL &#62;SELECT PARTITION_NAME, TABLE_ROWSFROM INFORMATION_SCHEMA.PARTITIONSWHERE TABLE_NAME = 'e';            ---------------- ------------ | partition_name | table_rows | ---------------- ------------ | P0 | 1 | | P1 | 0 | | P2 | 0 | | P3 | 3 | ---------------- ------------ 4行集(0秒)

现在我们再次交换分区p0E2使用相同的ALTER TABLE声明之前:

MySQL的&#62;ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2;查询行,0行受影响(0.28秒)

以下查询输出显示的表行存储在分区p0和表行存储在表E2发行前,ALTER TABLE声明,现在换了个地方:

MySQL的&#62;SELECT * FROM e;------ ------- ------- | ID |名| LName | ------ ------- ------- | 16 |弗兰克|白| | 1669 |吉姆|史米斯| | 337 |玛丽|琼斯| | 2005 |琳达|黑| ------ ------- ------- 4行集(0秒)MySQL &#62;SELECT PARTITION_NAME, TABLE_ROWSFROM INFORMATION_SCHEMA.PARTITIONSWHERE TABLE_NAME = 'e';---------------- ------------ | partition_name | table_rows | ---------------- ------------ | P0 | 1 | | P1 | 0 | | P2 | 0 | | P3 | 3 | ---------------- ------------ 4行集(0秒)MySQL &#62;SELECT * FROM e2;---- --------- ------- | ID |名| LName | ---- --------- ------- | 41 |米迦勒|绿色| ---- --------- ------- 1行集(0秒)

不匹配的行

你应该记住,任何行中发现的未分区表发行前ALTER TABLE ... EXCHANGE PARTITION语句必须满足他们被存储在目标分区的必要条件;否则,该语句将失败。看到这是如何发生的,先插入一行插入E2这是在分区的分区定义的界限p0E。例如,插入一行一个id列的值太大;然后,试着交换表分区了:

MySQL的&#62;INSERT INTO e2 VALUES (51, "Ellen", "McDonald");查询行,1行的影响(0.08秒)MySQL &#62;ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2;错误1707(hy000):发现行不匹配的分区

只有WITHOUT VALIDATION选择是否允许此操作成功:

MySQL的&#62;ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2 WITHOUT VALIDATION;查询行,0行受影响(0.02秒)

当一个分区是一个表包含不匹配的行的分区定义的交换,它是数据库管理员的责任来解决不匹配的行,可以使用REPAIR TABLEALTER TABLE ... REPAIR PARTITION

交换分区没有逐行验证

为了避免耗时的验证时,交换分区表有很多行,它可以通过行验证步骤添加跳过行WITHOUT VALIDATIONALTER TABLE ... EXCHANGE PARTITION声明

下面的示例将在执行的时候,交换分区和非分区表的差异,并没有验证。分区表(表e)包含两个分区100万排每。在P0表的行被移除,P0是1万行非分区表交换。这个与验证操作需要0.74秒。通过比较,该WITHOUT VALIDATION操作需要0.01秒

# Create a partitioned table with 1 million rows in each partitionCREATE TABLE e (    id INT NOT NULL,    fname VARCHAR(30),    lname VARCHAR(30))    PARTITION BY RANGE (id) (        PARTITION p0 VALUES LESS THAN (1000001),        PARTITION p1 VALUES LESS THAN (2000001),);mysql> SELECT COUNT(*) FROM e;                                             | COUNT(*) |+----------+|  2000000 |+----------+1 row in set (0.27 sec)# View the rows in each partitionSELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'e';+----------------+-------------+| PARTITION_NAME | TABLE_ROWS  |+----------------+-------------+| p0             |     1000000 || p1             |     1000000 |+----------------+-------------+2 rows in set (0.00 sec)# Create a nonpartitioned table of the same structure and populate it with 1 million rowsCREATE TABLE e2 (    id INT NOT NULL,    fname VARCHAR(30),    lname VARCHAR(30));mysql> SELECT COUNT(*) FROM e2;+----------+| COUNT(*) |+----------+|  1000000 |+----------+1 row in set (0.24 sec)# Create another nonpartitioned table of the same structure and populate it with 1 million rowsCREATE TABLE e3 (    id INT NOT NULL,    fname VARCHAR(30),    lname VARCHAR(30));    mysql> SELECT COUNT(*) FROM e3;+----------+| COUNT(*) |+----------+|  1000000 |+----------+1 row in set (0.25 sec)# Drop the rows from p0 of table emysql> DELETE FROM e WHERE id < 1000001;Query OK, 1000000 rows affected (5.55 sec)# Confirm that there are no rows in partition p0mysql> SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'e';+----------------+------------+| PARTITION_NAME | TABLE_ROWS |+----------------+------------+| p0             |          0 || p1             |    1000000 |+----------------+------------+2 rows in set (0.00 sec)    # Exchange partition p0 of table e with the table e2 'WITH VALIDATION'mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2 WITH VALIDATION;Query OK, 0 rows affected (0.74 sec)# Confirm that the partition was exchanged with table e2mysql> SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'e';+----------------+------------+| PARTITION_NAME | TABLE_ROWS |+----------------+------------+| p0             |    1000000 || p1             |    1000000 |+----------------+------------+2 rows in set (0.00 sec)# Once again, drop the rows from p0 of table emysql> DELETE FROM e WHERE id < 1000001;Query OK, 1000000 rows affected (5.55 sec)# Confirm that there are no rows in partition p0mysql> SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'e';+----------------+------------+| PARTITION_NAME | TABLE_ROWS |+----------------+------------+| p0             |          0 || p1             |    1000000 |+----------------+------------+2 rows in set (0.00 sec)# Exchange partition p0 of table e with the table e3 'WITHOUT VALIDATION'mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e3 WITHOUT VALIDATION;Query OK, 0 rows affected (0.01 sec)# Confirm that the partition was exchanged with table e3mysql> SELECT PARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'e';+----------------+------------+| PARTITION_NAME | TABLE_ROWS |+----------------+------------+| p0             |    1000000 || p1             |    1000000 |+----------------+------------+2 rows in set (0.00 sec)

如果一个分区是一个表包含不匹配的行的分区定义的交换,它是数据库管理员的责任来解决不匹配的行,可以使用REPAIR TABLEALTER TABLE ... REPAIR PARTITION

与非分区表交换子

你也可以换一个subpartitioned子表(见第22.2.6,“subpartitioning”)与非分区表使用ALTER TABLE ... EXCHANGE PARTITION声明。在下面的示例中,我们先创建一个表这是分区的RANGE通过与subpartitioned钥匙,填充此表为我们做表e,然后创建一个空的,未分区的复制沙二段的表,如下所示:

mysql> CREATE TABLE es (
    ->     id INT NOT NULL,
    ->     fname VARCHAR(30),
    ->     lname VARCHAR(30)
    -> )
    ->     PARTITION BY RANGE (id)
    ->     SUBPARTITION BY KEY (lname)
    ->     SUBPARTITIONS 2 (
    ->         PARTITION p0 VALUES LESS THAN (50),
    ->         PARTITION p1 VALUES LESS THAN (100),
    ->         PARTITION p2 VALUES LESS THAN (150),
    ->         PARTITION p3 VALUES LESS THAN (MAXVALUE)
    ->     );
Query OK, 0 rows affected (2.76 sec)

mysql> INSERT INTO es VALUES
    ->     (1669, "Jim", "Smith"),
    ->     (337, "Mary", "Jones"),
    ->     (16, "Frank", "White"),
    ->     (2005, "Linda", "Black");
Query OK, 4 rows affected (0.04 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> CREATE TABLE es2 LIKE es;
Query OK, 0 rows affected (1.27 sec)

mysql> ALTER TABLE es2 REMOVE PARTITIONING;
Query OK, 0 rows affected (0.70 sec)
Records: 0  Duplicates: 0  Warnings: 0

虽然我们没有明确的名字,任何关于创建表时es,我们可以获得产生这些包括名字subpartition _名称列的PARTITIONSinformation_schema当选择从表,如下所示:

mysql> SELECT PARTITION_NAME, SUBPARTITION_NAME, TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'es';
+----------------+-------------------+------------+
| PARTITION_NAME | SUBPARTITION_NAME | TABLE_ROWS |
+----------------+-------------------+------------+
| p0             | p0sp0             |          1 |
| p0             | p0sp1             |          0 |
| p1             | p1sp0             |          0 |
| p1             | p1sp1             |          0 |
| p2             | p2sp0             |          0 |
| p2             | p2sp1             |          0 |
| p3             | p3sp0             |          3 |
| p3             | p3sp1             |          0 |
+----------------+-------------------+------------+
8 rows in set (0.00 sec)

以下ALTER TABLE隐含分区表p3sp0es与非分区表沙二段

mysql> ALTER TABLE es EXCHANGE PARTITION p3sp0 WITH TABLE es2;
Query OK, 0 rows affected (0.29 sec)

您可以验证该行发出以下查询交换:

mysql> SELECT PARTITION_NAME, SUBPARTITION_NAME, TABLE_ROWS
    ->     FROM INFORMATION_SCHEMA.PARTITIONS
    ->     WHERE TABLE_NAME = 'es';
+----------------+-------------------+------------+
| PARTITION_NAME | SUBPARTITION_NAME | TABLE_ROWS |
+----------------+-------------------+------------+
| p0             | p0sp0             |          1 |
| p0             | p0sp1             |          0 |
| p1             | p1sp0             |          0 |
| p1             | p1sp1             |          0 |
| p2             | p2sp0             |          0 |
| p2             | p2sp1             |          0 |
| p3             | p3sp0             |          0 |
| p3             | p3sp1             |          0 |
+----------------+-------------------+------------+
8 rows in set (0.00 sec)

mysql> SELECT * FROM es2;
+------+-------+-------+
| id   | fname | lname |
+------+-------+-------+
| 1669 | Jim   | Smith |
|  337 | Mary  | Jones |
| 2005 | Linda | Black |
+------+-------+-------+
3 rows in set (0.00 sec)

如果一个表subpartitioned,你可以交换只有一子分区表的分区表不是一整个分区,如下所示:

mysql> ALTER TABLE es EXCHANGE PARTITION p3 WITH TABLE es2;
ERROR 1704 (HY000): Subpartitioned table, use subpartition instead of partition

在一个严格的方式比较表结构;数量,顺序,名字,和列和分区表的索引和非分区表类型必须精确匹配。此外,这两个表都必须使用相同的存储引擎:

mysql> CREATE TABLE es3 LIKE e;
Query OK, 0 rows affected (1.31 sec)

mysql> ALTER TABLE es3 REMOVE PARTITIONING;
Query OK, 0 rows affected (0.53 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE es3\G
*************************** 1. row ***************************
       Table: es3
Create Table: CREATE TABLE `es3` (
  `id` int(11) NOT NULL,
  `fname` varchar(30) DEFAULT NULL,
  `lname` varchar(30) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> ALTER TABLE es3 ENGINE = MyISAM;
Query OK, 0 rows affected (0.15 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE es EXCHANGE PARTITION p3sp0 WITH TABLE es3;
ERROR 1497 (HY000): The mix of handlers in the partitions is not allowed in this version of MySQL

22.3.4维护分区

多个表和分区的维护任务可以对分区使用SQL语句用于这种目的表进行。

表分区表维护可以使用语句完成CHECK TABLEOPTIMIZE TABLEANALYZE TABLE,和REPAIR TABLEpartitioned,which are for表支持。

你可以使用一些扩展ALTER TABLE这种类型的一个或多个分区进行操作,如下所示:

  • partitions重建。重建分区;这具有相同的效果,删除所有记录存储在分区,然后重新插入它们。这可以用碎片整理是有用的。

    例子:

    ALTER TABLE t1 REBUILD PARTITION p0, p1;
    
  • 优化分区如果您已经删除了大量的行从一个分区或如果你已经有了许多改变分区表与可变长度列(即有VARCHARBLOB,或TEXT列),你可以使用ALTER TABLE ... OPTIMIZE PARTITION回收未使用的空间和整理的分区中的数据文件。

    例子:

    ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;
    

    使用OPTIMIZE PARTITION在一个给定的分区相当于跑检查分区ANALYZE PARTITION,和修复分区分区上的

    一些MySQL存储引擎,包括InnoDB,不支持在这些情况下,每个分区的优化,ALTER TABLE ... OPTIMIZE PARTITION分析并重建整个表,使一个适当的警告发出。(错误# 11751825,错误# 42822)使用修改表…重建分区ALTER TABLE ... ANALYZE PARTITION相反,为了避免这个问题。

  • 分析分区这种读取和存储分区的主要分布。

    例子:

    ALTER TABLE t1 ANALYZE PARTITION p3;
    
  • 修复分区这修理损坏的分区

    例子:

    ALTER TABLE t1 REPAIR PARTITION p0,p1;
    

    通常,REPAIR PARTITION失败时的分区包含重复键错误。你可以使用ALTER IGNORE TABLE使用此选项,在这种情况下,所有的行,不能移动,由于重复键的存在是从分区删除(bug # 16900947)。

  • 检查的分区你可以检查在多,你可以用同样的方式错误的分区CHECK TABLE与已分区表

    例子:

    ALTER TABLE trb3 CHECK PARTITION p1;
    

    这个命令会告诉你是否在分区中的数据或索引p1T1损坏。如果是这种情况,使用ALTER TABLE ... REPAIR PARTITION修复分区

    通常,CHECK PARTITION失败时的分区包含重复键错误。你可以使用ALTER IGNORE TABLE使用此选项,在这种情况下,该语句将返回每一行的内容在分区复制钥匙发现违规。只报告的值列在分区表达的表。(错误# 16900947)

每个报表列表中只显示也支持关键字ALL在分配名单的地方。使用全部导致语句作用于表中的所有分区。

你也可以使用TRUNCATE分区ALTER TABLE ... TRUNCATE PARTITION。这句话可以用来删除所有记录从一个或多个分区在大致相同的方式,TRUNCATE TABLE从表中删除所有行

ALTER TABLE ... TRUNCATE PARTITION ALL将表中的所有分区

22.3.5获得信息的分区

本节讨论获取现有的分区信息,可以在许多方面做了。获取这些信息的方法,包括以下:

在本章中其他地方讨论,SHOW CREATE TABLE包括在其输出分区用于创建一个分区表条款。例如:

mysql> SHOW CREATE TABLE trb3\G
*************************** 1. row ***************************
       Table: trb3
Create Table: CREATE TABLE `trb3` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `purchased` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE (YEAR(purchased))
(PARTITION p0 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB) */
0 row in set (0.00 sec)

从输出SHOW TABLE STATUS对于分区表是一样的,非分区表,除了那创造性的选择列包含的字符串partitioned。这个引擎列包含所有分区的表使用的存储引擎的名称。(见第13.7.6.36,“显示表状态语法”,有关此声明的更多信息。)

你也可以获取分区信息INFORMATION_SCHEMA,其中包含一个PARTITIONS表看到24.14节,“information_schema分区表”

可以确定分区的分区表中给定的SELECT查询使用EXPLAIN。这个分区列在EXPLAIN输出列表分区的记录将被查询匹配。

假设一个表trb1创建并填充如下:

以创建表(ID int,NAME varchar(50),购买日期)按范围分区(ID)(分区P0值小于(3),分区P1值小于(7),分区P2的值小于(9),分区P3值小于(11));插入以价值(1台组织者&#39;,&#39; 2003-10-15”),(2,“CD播放器”、“1993-11-05”),(3,“电视机”、“1996-03-10”),(4,“书架”、“1982-01-10”),(5,“自行车运动”,“2004-05-09”),(6,“沙发”、“1987-06-05”),(7,“爆米花机”、“2001-11-22”),(8,“水族馆”、“1992-08-04”),(9,“书桌”、“1984-09-16”),(10,“熔岩灯”、“1998-12-25”);

你可以看到哪些分区是用于查询等SELECT * FROM trb1;,如下所示:

MySQL的&#62;EXPLAIN SELECT * FROM trb1\G*************************** 1。行***************************编号:1 select_type:简单表:以P0,P1,P2分区,P3型:allpossible_keys:空键:空key_len:零号:空10行:额外的:使用filesort

在这种情况下,所有四个分区进行搜索。然而,当一个限制条件使用分区键添加到查询中,你可以看到,只有那些分区包含匹配值进行扫描,如图所示:

mysql> EXPLAIN SELECT * FROM trb1 WHERE id < 5\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: trb1
   partitions: p0,p1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 10
        Extra: Using where

EXPLAIN 还提供了使用和可能的密钥密钥的信息:

MySQL的&#62;ALTER TABLE trb1 ADD PRIMARY KEY (id);查询行,10行受影响(0.03秒)记录:10份:0警告:0mysql &#62;EXPLAIN SELECT * FROM trb1 WHERE id < 5\G*************************** 1。行***************************编号:1 select_type:简单表:以分区:P0、P1型:rangepossible_keys:主键:主要key_len:4编号:空7行:额外使用的地方:

如果EXPLAIN用于检查对未分区表的查询,不产生误差,但价值的分区柱总是NULL

这个rowsEXPLAIN输出显示表中的行的总数。

参见第13.8.2,”解释语法”

22.4分区修剪

优化称为分区裁剪是基于一个相对简单的概念,它可以被描述为不扫描的分区,那里可没有匹配的值。假设一个分区表t1由这个语句创建:

create table(T1 fname varchar(50)不为零,lname varchar(50)不为零,代码区_ tinyint unsigned空槽,空槽的DOB的日期范围分区(市)区_ Code)(P值小于分区(partition),P1值小于(128),P2的值较小的分区比(192),分区P3值小于MaxValue);

假设你希望从得到的结果SELECT如这一声明:

SELECT fname, lname, region_code, dob    FROM t1    WHERE region_code > 125 AND region_code < 130;

显而易见,该行被返回没有任何分区p0P3;即我们只需要搜索分区p1P2找到匹配的行。通过限制搜索,可以花费更少的时间和精力在寻找比表中的行扫描所有分区匹配。这切掉不必要的分区被称为修剪。当优化器可以执行此查询利用分区修剪,查询执行的是一个数量级的速度比与非分区表包含相同的列定义和数据相同的查询。

优化器可以执行修剪时WHERE条件可归结为以下两种情况之一:

  • partition_column = constant

  • partition_column IN (constant1, constant2, ..., constantN)

在第一种情况下,优化器简单评价分区表达式给出的值,确定哪个分区中包含的价值,和只扫描这个分区。在许多情况下,等号可以与其他算法的比较所取代,包括<&#62;<=>=,和<>。某些查询使用之间WHERE条款还可以利用分区修剪。在本节稍后看到的例子。

在第二种情况下,优化器在列表分区表达每个价值评价,创建一个列表中匹配的分区,然后扫描的分区在分区表。

SELECTDELETE,和UPDATE报表支持分区修剪INSERT陈述目前不能修剪

修剪还可以应用于短距离,而优化器可以转换成值对照表。例如,在前面的例子中,该WHERE条款可转换为在region_code在(126, 127, 128,129)。那么优化器可以确定列表中的第一个值被发现在分区p1,其余两值划分P2,而其他的分区包含不相关的价值观,所以不需要寻找匹配的行。

优化器还可以进行修剪WHERE涉及上述类型的表,使用多个列的比较条件范围列LIST COLUMNS分区

这种优化可以应用在分区的表达由一个平等或范围,可以减少到一组等式,或当分区表示增加或减少的关系。修剪也可以用于分区表上DATEDATETIME柱当分区表达式使用YEAR()TO_DAYS()功能。修剪也可以用于这样的表格时,分区表达式使用TO_SECONDS()功能

假设表t2分区上,DATE柱,利用这里显示的语句创建:

create table(T2 fname varchar(50)不为零,lname varchar(50)不为零,代码区_ tinyint unsigned空槽,空槽的DOB的日期范围分区(市)年(DOB)(partition)D0值小于(1970),分区D1的值小于(1975),D2值分配低于(1980),分区值小于D3(1985年)、D4值小于分区的分区(1990),D5的值小于(2000),D6值小于分区(partition),2005年D7值小于MaxValue);

下面的语句使用t2可以使用分区修剪:

SELECT * FROM t2 WHERE dob = '1982-06-23';UPDATE t2 SET region_code = 8 WHERE dob BETWEEN '1991-02-15' AND '1997-04-25';DELETE FROM t2 WHERE dob >= '1984-06-21' AND dob <= '1999-06-21'

在最后陈述时,优化器也可采取如下:

  1. 找到包含该范围的低端的划分

    YEAR('1984-06-21')收益率的价值一千九百八十四,这是发现在分区d3

  2. 找到包含高端的范围划分

    YEAR('1999-06-21')评价一千九百九十九,这是发现在分区d5

  3. 只扫描这两个分区,可能是它们之间的任何分区

    在这种情况下,这意味着只有分区d3D4,和d5扫描。剩下的分区可以安全地忽略(被忽略)。

重要

无效DATE日期时间在参考值WHERE对分区表语句条件为无效的。。。。。。。这意味这一个查询如SELECT * FROM partitioned_table WHERE date_column < '2008-12-00'不返回任何值(见虫# 40972)。

到目前为止,我们只看实例RANGE分区修剪,但可以应用于其他类型的划分以及。

考虑到已分区表的LIST,其中的分区表达的增加或减少,如表T3这里显示的。(在这个例子中,我们假设为简洁起见,region_code柱是限于1和10之间的包容性的价值。)

create table(T3)fname varchar(50)不为零,lname varchar(50)不为零,代码区_ tinyint unsigned空槽,空槽的DOB约会列表(市)区的分区(partition _ Code)R0值在(1,3)分区,在R1的值(2,5,8),在分区的R2值(4,9),(partition R3的值在6,7,10);

对于这样一个语句SELECT * FROM t3 WHERE region_code BETWEEN 1 AND 3,优化器在将值1,2,和3被发现(R0r1)和跳过其余的(R2r3

partitioned by that are for表HASH[线性]键分区修剪,也有可能在案件中WHERE子句中使用一个简单的=关系对用于划分表达柱。考虑一个表创建这样的:

CREATE TABLE t4 (
    fname VARCHAR(50) NOT NULL,
    lname VARCHAR(50) NOT NULL,
    region_code TINYINT UNSIGNED NOT NULL,
    dob DATE NOT NULL
)
PARTITION BY KEY(region_code)
PARTITIONS 8;

一个声明比较列值与一个常数可以修剪:

UPDATE t4 WHERE region_code = 7;

修剪还可用于短距离,因为优化器可以把这样的条件IN关系.例如,使用相同的表T4正如先前定义的查询,如这些可修剪:

SELECT * FROM t4 WHERE region_code > 2 AND region_code < 6;

SELECT * FROM t4 WHERE region_code BETWEEN 3 AND 5;

在这些情况下,的WHERE条款由优化器在region_code在(3,4,5)

重要

这种优化是只有范围大小小于分区的数目。考虑这一说法:

DELETE FROM t4 WHERE region_code BETWEEN 4 AND 12;

在范围WHERE条款包括9值(4, 5, 6,7, 8, 9,10, 11, 12),但T4只有8个部分。这就是这个DELETE不能修剪

当一个表分区HASH[线性]键,修剪只能用于整数列。例如,这一声明不能使用修剪因为dob是一个DATE专栏

SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';

然而,如果在一个表中存储一年的价值INT柱,然后查询有WHERE year_col >= 2001 AND year_col <= 2005可以修剪

使用存储引擎,提供了自动分区表,如NDBMySQL集群使用的存储引擎(目前不支持MySQL 8),可以修剪的如果他们明确划分。

2.2.5分区选择

匹配给定的分区和子分区明确的选择行WHERE条件支持。分区选择类似于分区修剪,只能在特定的分区进行比赛,但不同的两个关键方面:

  1. 要检查的分区是通过声明发行人指定,不像分区修剪,这是自动的。

  2. 而分区修剪仅适用于查询,分区明确的选择是查询和多个DML语句支持。

SQL语句显式分区选择如下:

本节讨论了明确的分区选择它一般适用于刚上市的报表,并提供了一些例子。

明确的分区选择使用PARTITION选项所有支持的陈述,这个选项使用下面的语法:

分区(partition_namespartition_namespartition_name,…

此选项始终遵循的表名称的分区或分区属于。partition_names是一个逗号分隔的列表分区和子分区可以使用。此列表中的每个名称必须是一个现有的分区和子分区的指定表的名称;如果任何分区和子分区都没有找到,该语句将失败与错误(分区”partition_name”不存在)。partitions和subpartitions名叫进来partition_names可以以任何顺序列出,并可以重叠。

PARTITION选项时,只有分区和子分区列检查匹配的行。此选项可用于SELECT语句来确定哪些行属于一个给定分区。考虑分区表命名员工,创建和填充使用这里显示的报表:

SET @@SQL_MODE = '';

CREATE TABLE employees  (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    fname VARCHAR(25) NOT NULL,
    lname VARCHAR(25) NOT NULL,
    store_id INT NOT NULL,
    department_id INT NOT NULL
) 
    PARTITION BY RANGE(id)  (
        PARTITION p0 VALUES LESS THAN (5),
        PARTITION p1 VALUES LESS THAN (10),
        PARTITION p2 VALUES LESS THAN (15),
        PARTITION p3 VALUES LESS THAN MAXVALUE
);

INSERT INTO employees VALUES
    ('', 'Bob', 'Taylor', 3, 2), ('', 'Frank', 'Williams', 1, 2),
    ('', 'Ellen', 'Johnson', 3, 4), ('', 'Jim', 'Smith', 2, 4),
    ('', 'Mary', 'Jones', 1, 1), ('', 'Linda', 'Black', 2, 3),
    ('', 'Ed', 'Jones', 2, 1), ('', 'June', 'Wilson', 3, 1),
    ('', 'Andy', 'Smith', 1, 3), ('', 'Lou', 'Waters', 2, 4),
    ('', 'Jill', 'Stone', 1, 4), ('', 'Roger', 'White', 3, 2),
    ('', 'Howard', 'Andrews', 1, 2), ('', 'Fred', 'Goldberg', 3, 3),
    ('', 'Barbara', 'Brown', 2, 3), ('', 'Alice', 'Rogers', 2, 2),
    ('', 'Mark', 'Morgan', 3, 3), ('', 'Karen', 'Cole', 3, 2);

你可以看到这行存储在分区p1这样地:

MySQL的&#62;SELECT * FROM employees PARTITION (p1);————————————————| -------选择ID | fname | L NAME |商店ID ID _ |部_ |——------- --------选择|玛丽琼斯| --------------- | 5 1 6 1 | | | | |琳达|黑| 2 3 7 | | | | ED | | 2 1 | |琼斯8月| | |威尔逊| 3 1 9 | | | |安迪史密斯| | | | 1——3——5 rows --------------- -------选择集(0秒)

其结果是通过查询获得相同SELECT * FROM employees WHERE id BETWEEN 5 AND 9

从多个分区中获得行,供应他们的名字作为一个逗号分隔的列表。例如,SELECT * FROM employees PARTITION (p1, p2)从分区返回所有行P1p2而不包括从其他分区的行。

对分区表的任何有效的查询重写可以用PARTITION选项来限制结果的一个或多个所需分区。你可以使用哪里条件,ORDER BY极限选项,等等。你也可以使用聚合函数HAVING选项下面的查询产生有效的结果在运行时employees表定义:

MySQL的&#62;SELECT * FROM employees PARTITION (p0, p2)-&#62;WHERE lname LIKE 'S%';---- ------- ------- ---------- --------------- | ID |名| LName | store_id | department_id | ---- ------- ------- ---------- --------------- | 4 |吉姆|史米斯| 2 | 4 | | 11 |吉尔|石| 1 | 4 | ---- ------- ------- ---------- --------------- 2行集(0秒)MySQL &#62;SELECT id, CONCAT(fname, ' ', lname) AS name-&#62;FROM employees PARTITION (p0) ORDER BY lname;---- ---------------- | ID |名字| ---- ---------------- | 3 | Ellen Johnson | | 4 | Jim Smith | | 1 |鲍勃·泰勒| | 2 | Frank Williams | ---- ---------------- 4行集(0.06秒)MySQL &#62;SELECT store_id, COUNT(department_id) AS c-&#62;FROM employees PARTITION (p1,p2,p3)-&#62;GROUP BY store_id HAVING c > 4;--- ---------- | C | store_id | --- ---------- | 5 | 2 | | 5 | 3 | --- ---------- 2行集(0秒)

使用分区选择语句可以使用任何支持的分区类型表。当一个表的创建[LINEAR] HASH[线性]键分区和分区的名称没有指定,MySQL自动命名的分区p0P1p2,…,PN-1,在那里N是分区的数量。为子分区不明确点名,MySQL将自动在每个分区的子分区PX的名字PXSP0PXSP1的PXSP2,…,PX服务提供商M-1,在那里M是不会数。当执行在此表SELECT(或其他SQL语句中显式分区的选择是允许的),你可以在使用这些生成的名称分区选项,如下图所示:

mysql> CREATE TABLE employees_sub  (
    ->     id INT NOT NULL AUTO_INCREMENT,
    ->     fname VARCHAR(25) NOT NULL,
    ->     lname VARCHAR(25) NOT NULL,
    ->     store_id INT NOT NULL,
    ->     department_id INT NOT NULL,
    ->     PRIMARY KEY pk (id, lname)
    -> ) 
    ->     PARTITION BY RANGE(id)
    ->     SUBPARTITION BY KEY (lname)
    ->     SUBPARTITIONS 2 (
    ->         PARTITION p0 VALUES LESS THAN (5),
    ->         PARTITION p1 VALUES LESS THAN (10),
    ->         PARTITION p2 VALUES LESS THAN (15),
    ->         PARTITION p3 VALUES LESS THAN MAXVALUE
    -> );
Query OK, 0 rows affected (1.14 sec)

mysql> INSERT INTO employees_sub   # reuse data in employees table
    ->     SELECT * FROM employees;
Query OK, 18 rows affected (0.09 sec)
Records: 18  Duplicates: 0  Warnings: 0

mysql> SELECT id, CONCAT(fname, ' ', lname) AS name
    ->     FROM employees_sub PARTITION (p2sp1);
+----+---------------+
| id | name          |
+----+---------------+
| 10 | Lou Waters    |
| 14 | Fred Goldberg |
+----+---------------+
2 rows in set (0.00 sec)

你也可以使用PARTITION选项中的SELECT部分的INSERT ... SELECT语句,如下所示:

MySQL的&#62;CREATE TABLE employees_copy LIKE employees;查询行,0行受影响(0.28秒)MySQL &#62;INSERT INTO employees_copy-&#62;SELECT * FROM employees PARTITION (p2);查询好了,五行受影响(0.04秒)记录:5重复:0警告:0mysql &#62;SELECT * FROM employees_copy;---- -------- ---------- ---------- --------------- | ID |名| LName | store_id | department_id | ---- -------- ---------- ---------- --------------- |十|娄|水域| 2 |四| | 11 |吉尔|石| 1 |四| | 12 |罗杰|白|三| 2 | | 13 |霍华德|安德鲁斯| 1 | 2 | | 14 |弗莱德|戈德堡|三|三| ---- -------- ---------- ---------- ---------------五行集(0.001秒)

分区选择也可以加入。假设我们创建和填充两表使用这里显示的报表:

CREATE TABLE stores (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    city VARCHAR(30) NOT NULL
)
    PARTITION BY HASH(id)
    PARTITIONS 2;
  
INSERT INTO stores VALUES
    ('', 'Nambucca'), ('', 'Uranga'),
    ('', 'Bellingen'), ('', 'Grafton');
  
CREATE TABLE departments  (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30) NOT NULL
)
    PARTITION BY KEY(id)
    PARTITIONS 2;
  
INSERT INTO departments VALUES
    ('', 'Sales'), ('', 'Customer Service'),
    ('', 'Delivery'), ('', 'Accounting');

你可以明确地选择分区(或子分区,或者两者都有)任何或所有在联接表。(ThePARTITION立即使用从一个给定的表选择分区选项如下表的名称,在所有其他的选项,包括任何表的别名。)例如,下面的查询对象的名称、员工编号、部门和城市的所有员工在销售或运输部(分区P1departments表)在商店是Nambucca市和贝林真市(分区P0stores表):

MySQL的&#62;SELECT-&#62;e.id AS 'Employee ID', CONCAT(e.fname, ' ', e.lname) AS Name,-&#62;s.city AS City, d.name AS department-&#62;FROM employees AS e-&#62;JOIN stores PARTITION (p1) AS s ON e.store_id=s.id-&#62;JOIN departments PARTITION (p0) AS d ON e.department_id=d.id-&#62;ORDER BY e.lname;------------- --------------- ----------- ------------ |雇员ID |名字|市|部| ------------- --------------- ----------- ------------ | 14 | Fred Goldberg |贝林真|交付| | 5 | Mary Jones |南巴卡|销售| | 17 | Mark Morgan |贝林真|交付| | 9 |安迪史密夫|南巴卡|交付| | 8 |月Wilson |贝林真|销售| ------------- --------------- ----------- ------------ 5行集(0秒)

对于一般的信息加入MySQL,看第13.2.10.2,加入“语法”

PARTITION选择使用DELETE报表,只有分区(和子分区,如果有)上市的选项是检查的行被删除。其他分区被忽视,如下所示:

MySQL的&#62;SELECT * FROM employees WHERE fname LIKE 'j%';---- ------- -------- ---------- --------------- | ID |名| LName | store_id | department_id | ---- ------- -------- ---------- --------------- |四|吉姆|史米斯| 2 |四| | 8 |月|威尔逊|三| 1 | | 11 |吉尔|石| 1 |四| ---- ------- -------- ---------- ---------------三行集(0.001秒)MySQL &#62;DELETE FROM employees PARTITION (p0, p1)-&#62;WHERE fname LIKE 'j%';查询行,2行受影响(0.09秒)MySQL &#62;SELECT * FROM employees WHERE fname LIKE 'j%';————————————| ------- -------选择ID | fname | L NAME |商店ID ID _ |部_ |——------- -------选择11 | --------------- |吉尔|石| 1——4 | | ------- -------选择1行到集(0秒)

只有两排在分区p0P1匹配WHERE条件被删除。正如你可以看到的结果时,SELECT运行一次,有一个表中的行匹配哪里条件,但居住在不同的分区(p2

UPDATE使用明确的分区选择语句的行为相同的方式;分区中的引用的行分区期权是在确定要更新的行,可以通过执行下面的语句看到:

mysql> UPDATE employees PARTITION (p0) 
    ->     SET store_id = 2 WHERE fname = 'Jill';
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0  Changed: 0  Warnings: 0

mysql> SELECT * FROM employees WHERE fname = 'Jill';
+----+-------+-------+----------+---------------+
| id | fname | lname | store_id | department_id |
+----+-------+-------+----------+---------------+
| 11 | Jill  | Stone |        1 |             4 |
+----+-------+-------+----------+---------------+
1 row in set (0.00 sec)

mysql> UPDATE employees PARTITION (p2)
    ->     SET store_id = 2 WHERE fname = 'Jill';
Query OK, 1 row affected (0.09 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT * FROM employees WHERE fname = 'Jill';
+----+-------+-------+----------+---------------+
| id | fname | lname | store_id | department_id |
+----+-------+-------+----------+---------------+
| 11 | Jill  | Stone |        2 |             4 |
+----+-------+-------+----------+---------------+
1 row in set (0.00 sec)

以同样的方式,当PARTITION使用DELETE,仅排在分区或分区,在分区列表中指定是否删除。

语句,插入行,行为的不同之处在于,未能找到一个合适的分区将导致语句失败。这是真实的INSERTREPLACE语句,如下所示:

MySQL的&#62;INSERT INTO employees PARTITION (p2) VALUES (20, 'Jan', 'Jones', 1, 3);错误1729(hy000):发现一行不匹配给定的分区设置MySQL的&#62;INSERT INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 1, 3);查询行,1行的影响(0.07秒)MySQL &#62;替换员工分区(P0)值(20,&#39;月&#39;,&#39;琼斯&#39;,3, 2);错误1729(hy000):发现一行不匹配给定的分区设置MySQL &#62;替换员工分区(P3)值(20,&#39;月&#39;,&#39;琼斯&#39;,3,2);查询行,2行受影响(0.09秒)

语句写多行的分区表,使用InnoDB存储引擎:如果任何排在名单如下价值观无法写入一个指定的分区partition_names列表,整个语句失败和没有行写。这是显示INSERT在下面的例子中的陈述,重用员工表格之前创建的:

mysql> ALTER TABLE employees
    ->     REORGANIZE PARTITION p3 INTO (
    ->         PARTITION p3 VALUES LESS THAN (20),
    ->         PARTITION p4 VALUES LESS THAN (25),
    ->         PARTITION p5 VALUES LESS THAN MAXVALUE
    ->     );
Query OK, 6 rows affected (2.09 sec)
Records: 6  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE employees\G
*************************** 1. row ***************************
       Table: employees
Create Table: CREATE TABLE `employees` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `fname` varchar(25) NOT NULL,
  `lname` varchar(25) NOT NULL,
  `store_id` int(11) NOT NULL,
  `department_id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8mb4
/*!50100 PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (5) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (15) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (20) ENGINE = InnoDB,
 PARTITION p4 VALUES LESS THAN (25) ENGINE = InnoDB,
 PARTITION p5 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

mysql> INSERT INTO employees PARTITION (p3, p4) VALUES
    ->     (24, 'Tim', 'Greene', 3, 1),  (26, 'Linda', 'Mills', 2, 1);
ERROR 1729 (HY000): Found a row not matching the given partition set

mysql> INSERT INTO employees PARTITION (p3, p4. p5) VALUES
    ->     (24, 'Tim', 'Greene', 3, 1),  (26, 'Linda', 'Mills', 2, 1);
Query OK, 2 rows affected (0.06 sec)
Records: 2  Duplicates: 0  Warnings: 0

前面的是真实的两个INSERT报表和REPLACE写多行语句

分区选择是使用存储引擎供应自动分区表禁用,如NDB(使用MySQL集群;目前不支持MySQL 8)。

在分区22.6限制

本节讨论MySQL分区支持电流限制。

禁止建构下面的结构是不允许分割的表达:

  • 程序的仓库,仓库的UDF函数,或插件。

  • 宣布或用户变量的变量。

一列的SQL函数的表达式允许分割,看第22.6.3,分区限制有关的功能”

算术运算符和逻辑运算符。使用算术运算符+-,和*在分区表达式允许。然而,结果是一个整型值或无效的(情况除外[LINEAR] KEY分区,是本章讨论的地方;看22.2节,“分区类型”,更多信息)

这个DIV运营商也支持的;/运营商是不允许的

位运算符|&^<<>>,和~不允许分割的表达

服务器的SQL模式使用用户定义的表分区不保存SQL模式在有效时间,他们创造了。其他本手册讨论(见第5.1.10,”服务器的SQL模式”),许多MySQL函数和操作符的结果可以根据服务器的SQL模式的变化。因此,在分区表创建后的任何时间在SQL模式的变化可能会导致这些表的行为也发生了重大的变化,很容易导致数据损坏或丢失。由于这些原因,我们强烈建议您不要更改服务器的SQL模式在创建分区表

实例下面的例子说明了在分区表中由于服务器的SQL模式改变行为的一些变化:

  1. 错误处理如在其他地方,处理特殊值为零,NULL可以在不同的服务器上的SQL模式之间的差异(见第5.1.10,”服务器的SQL模式”)。例如,ERROR_FOR_DIVISION_BY_ZERO是否会影响0可以插入一个值为表其分配表达式使用columnDIVvaluecolumn国防部value

  2. 表访问有时在服务器的SQL模式的变化可以使分区表的使用。以下CREATE TABLE语句可以执行成功只有NO_UNSIGNED_SUBTRACTION模式影响:

    MySQL的&#62;SELECT @@sql_mode;------------ | @ @ sql_mode | ------------ | | ------------ 1行集(0秒)MySQL &#62;CREATE TABLE tu (c1 BIGINT UNSIGNED)-&#62;PARTITION BY RANGE(c1 - 10) (-&#62;PARTITION p0 VALUES LESS THAN (-5),-&#62;PARTITION p1 VALUES LESS THAN (0),-&#62;PARTITION p2 VALUES LESS THAN (5),-&#62;PARTITION p3 VALUES LESS THAN (10),-&#62;PARTITION p4 VALUES LESS THAN (MAXVALUE)-&#62;);(hy000):错误1563年分配常数不分区函数域MySQL的&#62;SET sql_mode='NO_UNSIGNED_SUBTRACTION';查询好,为受影响的行(0.001秒)MySQL &#62;SELECT @@sql_mode;------------------------- | @ @ sql_mode | ------------------------- | no_unsigned_subtraction | ------------------------- 1行集(0秒)MySQL &#62;CREATE TABLE tu (c1 BIGINT UNSIGNED)-&#62;PARTITION BY RANGE(c1 - 10) (-&#62;PARTITION p0 VALUES LESS THAN (-5),-&#62;PARTITION p1 VALUES LESS THAN (0),-&#62;PARTITION p2 VALUES LESS THAN (5),-&#62;PARTITION p3 VALUES LESS THAN (10),-&#62;PARTITION p4 VALUES LESS THAN (MAXVALUE)-&#62;);查询行,0行受影响(0.05秒)

    如果删除NO_UNSIGNED_SUBTRACTION在创建SQL Server模式,你可能不再能够访问此表:

    mysql> SET sql_mode='';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> SELECT * FROM tu;
    ERROR 1563 (HY000): Partition constant is out of partition function domain
    mysql> INSERT INTO tu VALUES (20);
    ERROR 1563 (HY000): Partition constant is out of partition function domain
    

    参见第5.1.10,”服务器的SQL模式”

服务器的SQL模式也影响复制分区表。不同的SQL模式对主人和奴隶可以导致分区表达式被评估的不同;这会导致数据分布在分区间是不同的在主人和奴隶的副本的一个给定的表,甚至可能造成插入分区表,成功在主对奴隶失败。为达到最佳效果,你应该总是使用相同的SQL Server模式对主人和奴隶。

业绩考量分区操作性能的一些影响在以下列表:

  • 文件系统操作分区和重新分区的操作(如ALTER TABLE分区…REORGANIZE PARTITION,或删除分区)取决于文件系统操作的实现。这意味着这些操作的速度是由文件系统的类型和特点,磁盘速度,交换空间等因素的影响,操作系统的文件处理的效率,和MySQL服务器选项和变量与文件处理。特别是,你应该确保large_files_support启用时,open_files_limit设置不当。分割和重组业务涉及InnoDB表格可以使更有效innodb_file_per_table

    参见分区最大数量

  • 表锁一般来说,处理一个表执行分区操作需要一个写在表锁。从表读取是相对不受影响;待定INSERTUPDATE操作是尽快进行分区操作完成。为InnoDB-这个限制特定的例外情况,看分配操作

  • 反射镜与非分区表,正确使用索引可以加快查询分区表的显著。此外,设计分区表和查询这些表的利用分区裁剪可以极大地提高性能。看到22.4节,“分区修剪”为更多的信息

    索引下推partitioned condition is for表支持。欧洲经济区第8.2.1.5,“指标条件下推优化”

  • 随着数据加载性能在MySQL 5.0,LOAD DATA使用缓冲以提高性能。你应该知道缓冲区使用130 KB的内存每个分区的实现。

分区最大数量在MySQL 8中,对于一个给定的表分区的最大可能数是8192。这个数字包括的子分区。

如果,创造大量的分区表时(但小于最大),你遇到一个错误信息等有错误…从存储引擎:从资源时,打开文件,你可以解决的问题,通过增加的价值open_files_limit系统变量。然而,这是依赖于操作系统,不可能在所有平台上可能或可取;看第b.5.2.17,“找不到文件和类似的错误”为更多的信息。在某些情况下,使用大量(数百个)分区,也不是由于其他问题是明智的,所以使用多个分区并不会自动导致更好的结果。

参见文件系统操作

外键不支持InnoDB表分区。分区表的使用InnoDB存储引擎不支持外键。更具体地说,这意味着以下两个陈述是真实的:

  1. 一个没有定义InnoDB采用用户自定义分区表可能包含外键引用;没有InnoDB表的定义包含外键引用可以划分。

  2. InnoDB表定义可能包含一个外键参照用户分区表;没有InnoDB用户定义的分区表可能包含外键引用的列。

刚刚上市的限制范围包括所有表使用InnoDB存储引擎CREATE TABLEALTER TABLE语句将导致违反这些限制的表是不允许的。

修改表…顺序一个ALTER TABLE ... ORDER BY column语句运行在分区表只能在每个分区的行排序。

在替代主键修改报表的影响。它可以在某些情况下是可取的(见“22.6.1分解段,原钥匙,钥匙和钥匙,独特的”)修改表的主键。要知道,如果你的应用程序使用REPLACE声明,你这样做,这些语句的结果可以大大改变。看到第13.2.9,”代替语法”,更多的信息和例子

全文索引分区表不支持FULLTEXTIndexes or search .

空间列空间数据类型如柱POINT几何cannot be used in分区表。

临时表临时表不能被分区

日志表它是不可能分割日志表;一ALTER TABLE ... PARTITION BY ...在这样一个表语句失败与错误。

关键日期型的分解分区键必须是一个整数列或表达式解析为一个整数。表达式使用ENUM列不能使用。列或表达式的值也可以无效的它;第22.2.7,“MySQL如何分割处理空”

但有两个例外限制:

  1. 当分区被[LINEAR]钥匙,它可以使用任何有效的MySQL数据列类型比其他TEXTBLOB作为分区键,因为内部密钥散列函数从这些类型产生正确的数据类型。例如,下面的两CREATE TABLE声明是有效的:

    创建表的TKC(C1 char)分区的分区键(C1)4;创建表TKE(C1枚举(红,橙,黄,绿,蓝,靛蓝&#39;,&#39;紫&#39;))通过线性关键分区(C1)分区6;
  2. 当分区RANGE COLUMNS表列,可以使用字符串,DATE,和DATETIME专栏例如,下面的CREATE TABLE报表是有效的:

    CREATE TABLE rc (c1 INT, c2 DATE)PARTITION BY RANGE COLUMNS(c2) (    PARTITION p0 VALUES LESS THAN(&#39;1990-01-01&#39;),    PARTITION p1 VALUES LESS THAN(&#39;1995-01-01&#39;),    PARTITION p2 VALUES LESS THAN(&#39;2000-01-01&#39;),    PARTITION p3 VALUES LESS THAN(&#39;2005-01-01&#39;),    PARTITION p4 VALUES LESS THAN(MAXVALUE));CREATE TABLE lc (c1 INT, c2 CHAR(1))PARTITION BY LIST COLUMNS(c2) (    PARTITION p0 VALUES IN(&#39;a&#39;, &#39;d&#39;, &#39;g&#39;, &#39;j&#39;, &#39;m&#39;, &#39;p&#39;, &#39;s&#39;, &#39;v&#39;, &#39;y&#39;),    PARTITION p1 VALUES IN(&#39;b&#39;, &#39;e&#39;, &#39;h&#39;, &#39;k&#39;, &#39;n&#39;, &#39;q&#39;, &#39;t&#39;, &#39;w&#39;, &#39;z&#39;),    PARTITION p2 VALUES IN(&#39;c&#39;, &#39;f&#39;, &#39;i&#39;, &#39;l&#39;, &#39;o&#39;, &#39;r&#39;, &#39;u&#39;, &#39;x&#39;, NULL));

上述例外情况不适用于BLOBTEXT列类型

子查询分区键可能无法查询,即使查询解析为一个整型值或NULL

与分区有关的问题subpartitions必须使用HASH钥匙分区。只有RANGE列表可subpartitioned分区;HASH钥匙不能subpartitioned分区。

SUBPARTITION BY KEY要求,分区列指定明确的情况下,与分区键,在那里可以省略(在这种情况下,表的主键列是默认使用)。考虑到该语句创建表:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
);

你可以创建一个具有相同的列表,分区KEY使用一个语句,如这一个:

创建表的TS(ID int不空auto_increment主键,名称为varchar(30))的key()分区4分区;

以前的说法是治疗好象是这样写的,与表的主键列作为分区列:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
)
PARTITION BY KEY(id)
PARTITIONS 4;
        

然而,下面的语句将尝试使用默认列作为分区列不能创建一个subpartitioned表和列必须为语句成功指定,如下所示:

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY()
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near ')

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY(id)
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.07 sec)

这是一个已知的问题(见虫# 51470)。

数据目录和索引目录选项。表级DATA DIRECTORY索引目录选项被忽略(见虫# 32091)。您可以使用这些选项的单个分区或子分区InnoDB

修复和重建分区表报表CHECK TABLEOPTIMIZE TABLEANALYZE TABLE,和REPAIR TABLEare for partitioned负载表。

此外,您可以使用ALTER TABLE ... REBUILD PARTITION一个或更多的重建分区表partitioned of a;修改表…重新分区另一个原因是重新建造。见第13.1.8,“ALTER TABLE语法”,关于这两个语句的更多信息。

ANALYZE检查OPTIMIZE修复,和TRUNCATE操作支持子分区。看到第13.1.8.1,“修改表分区操作”

原发性22.6.1分解钥匙和钥匙,钥匙,特制

本节讨论与主键和唯一键的分区键的关系。的规律,这种关系可以表示如下:用于划分表达对于分区表的所有列必须是每一个独特的关键,表可能有部分。

换句话说,桌上的每一个独特的钥匙必须在表的分区表达式中使用的每一列。(这也包括表的主键,因为它是通过定义一个独特的关键。这种特殊的情况下是在后面讨论。)例如,以下各表的创建语句是无效的:

CREATE TABLE t1 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    UNIQUE KEY (col1, col2)
)
PARTITION BY HASH(col3)
PARTITIONS 4;

CREATE TABLE t2 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    UNIQUE KEY (col1),
    UNIQUE KEY (col3)
)
PARTITION BY HASH(col1 + col3)
PARTITIONS 4;

在每一种情况下,该表将至少有一个独特的关键,不包括用于划分表达所有列。

下面的语句是有效的,并代表一种相应的无效创建表的语句可以工作:

CREATE TABLE t1 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    UNIQUE KEY (col1, col2, col3)
)
PARTITION BY HASH(col3)
PARTITIONS 4;

CREATE TABLE t2 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    UNIQUE KEY (col1, col3)
)
PARTITION BY HASH(col1 + col3)
PARTITIONS 4;

这个例子表明,在这种情况下产生的误差:

mysql> CREATE TABLE t3 (
    ->     col1 INT NOT NULL,
    ->     col2 DATE NOT NULL,
    ->     col3 INT NOT NULL,
    ->     col4 INT NOT NULL,
    ->     UNIQUE KEY (col1, col2),
    ->     UNIQUE KEY (col3)
    -> )
    -> PARTITION BY HASH(col1 + col3)
    -> PARTITIONS 4;
ERROR 1491 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

这个CREATE TABLE语句失败,因为2col3包括在建议的分区键列,但这些都是餐桌上的两个唯一键的一部分。这表明无效表定义一个可能的修复:

MySQL的&#62;CREATE TABLE t3 (-&#62;col1 INT NOT NULL,-&#62;col2 DATE NOT NULL,-&#62;col3 INT NOT NULL,-&#62;col4 INT NOT NULL,-&#62;UNIQUE KEY (col1, col2, col3),-&#62;UNIQUE KEY (col3)-&#62;)-&#62;PARTITION BY HASH(col3)-&#62;PARTITIONS 4;查询行,0行受影响(0.05秒)

在这种情况下,该分区键col3是一个独特的关键部分,和表的创建语句成功。

下表不能被分区的所有,因为没有办法包括在分区键的任何列,属于独特的钥匙:

CREATE TABLE t4 (
    col1 INT NOT NULL,
    col2 INT NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    UNIQUE KEY (col1, col3),
    UNIQUE KEY (col2, col4)
);

因为每一个主键是通过定义一个独特的关键,这个限制也包括表的主键,如果它有一个。例如,下面两个语句是无效的:

CREATE TABLE t5 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    PRIMARY KEY(col1, col2)
)
PARTITION BY HASH(col3)
PARTITIONS 4;

CREATE TABLE t6 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    PRIMARY KEY(col1, col3),
    UNIQUE KEY(col2)
)
PARTITION BY HASH( YEAR(col2) )
PARTITIONS 4;

在这两种情况下,主键不包括所有列在分区表达式引用。然而,这两个陈述是有效的:

CREATE TABLE t7 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    PRIMARY KEY(col1, col2)
)
PARTITION BY HASH(col1 + YEAR(col2))
PARTITIONS 4;

CREATE TABLE t8 (
    col1 INT NOT NULL,
    col2 DATE NOT NULL,
    col3 INT NOT NULL,
    col4 INT NOT NULL,
    PRIMARY KEY(col1, col2, col4),
    UNIQUE KEY(col2, col1)
)
PARTITION BY HASH(col1 + YEAR(col2))
PARTITIONS 4;

如果表没有唯一键,这包括没有主键则不在此限,你可以使用分区表达的任何列只要列式与分区类型兼容。

出于同样的原因,你不能在以后添加一个独特的关键分区表除非主要包括表的分区表达式中使用的所有列。考虑分区表创建如下所示:

mysql> CREATE TABLE t_no_pk (c1 INT, c2 INT)
    ->     PARTITION BY RANGE(c1) (
    ->         PARTITION p0 VALUES LESS THAN (10),
    ->         PARTITION p1 VALUES LESS THAN (20),
    ->         PARTITION p2 VALUES LESS THAN (30),
    ->         PARTITION p3 VALUES LESS THAN (40)
    ->     );
Query OK, 0 rows affected (0.12 sec)

它可以添加一个主键t_no_pk使用这些ALTER TABLE声明:

可能的ALTER TABLE t_no_pk ADD PRIMARY KEY(c1);查询行,0行受影响(0.13秒)记录:0份:0警告:0 #降本pkmysql &#62;ALTER TABLE t_no_pk DROP PRIMARY KEY;查询行,0行受影响(0.10秒)记录:0份:0警告:0 #使用另一个可能的pkmysql &#62;ALTER TABLE t_no_pk ADD PRIMARY KEY(c1, c2);查询行,0行受影响(0.12秒)记录:0份:0警告:0 #降本pkmysql &#62;ALTER TABLE t_no_pk DROP PRIMARY KEY;查询行,0行受影响(0.09秒)记录:0份:0警告:0

然而,接下来的语句失败,因为c1是分区键的一部分,但不是该主键的一部分:

#失败与错误1503mysql &#62;ALTER TABLE t_no_pk ADD PRIMARY KEY(c2);错误1503(hy000):主键必须包括表中的所有列的分区函数

t_no_pk只有C1在其划分的表达,试图添加一个独特的关键c2一个人失败。然而,你可以添加一个独特的关键,同时使用C1c2

这些规则也适用于现有的非分区表,你希望的分区使用ALTER TABLE ... PARTITION BY。考虑一个表np_pk创建如下所示:

mysql> CREATE TABLE np_pk (
    ->     id INT NOT NULL AUTO_INCREMENT,
    ->     name VARCHAR(50),
    ->     added DATE,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.08 sec)

以下ALTER TABLE语句失败与错误,因为补充柱不是表中的任何独特的关键部分:

mysql> ALTER TABLE np_pk
    ->     PARTITION BY HASH( TO_DAYS(added) )
    ->     PARTITIONS 4;
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

然而,这一声明中使用id为分区列列是有效的,如下所示:

MySQL的&#62;ALTER TABLE np_pk-&#62;PARTITION BY HASH(id)-&#62;PARTITIONS 4;查询行,0行受影响(0.11秒)记录:0份:0警告:0

在的情况下np_pk,只有柱可作为分区表达式的一部分身份证件;如果你希望进行分区表使用的任何其他列在分区表达式,你必须先修改表,通过添加所需的列或列的主键,或删除主键共。

22.6.2划分的局限性与存储引擎

在MySQL 5.0,分区的支持是不实际的MySQL服务器提供的,而是由一个表存储引擎自身或本地分区处理。在MySQL 8中,只有InnoDB存储引擎提供了本地分区处理。这意味着分区表不能使用任何其他存储引擎创建的。

笔记

MySQL集群NDB存储引擎还提供了本地分区的支持,但目前不在MySQL 8的支持。

ALTER TABLE ... OPTIMIZE PARTITION没有分区表,使用正确的工作InnoDB。使用ALTER TABLE ... REBUILD PARTITION修改表…分析分区,相反,这样的表。有关更多信息,参见第13.1.8.1,“修改表分区操作”

partitioned表1。执行升级时,表分区的KEY必须抛弃和重装上阵。分区使用存储引擎的表以外的InnoDB不能从MySQL 5.7或更早版本升级到MySQL 8或更高版本;必须删除该分区表ALTER TABLE ... REMOVE PARTITIONING或将其转换为InnoDB使用ALTER TABLE ... ENGINE=INNODB在升级之前

有关转换MyISAMInnoDB,看到第15.8.1.4”转换表,从MyISAM到InnoDB”

22.6.3划分的局限性与功能

本节讨论MySQL分区专门用于划分表达功能的局限性。

只有MySQL功能显示在以下列表中的表达式允许分区:

在MySQL 8中,分区修剪是支持的TO_DAYS()TO_SECONDS()YEAR(),和UNIX_TIMESTAMP()功能.看到22.4节,“分区修剪”为更多的信息

ceiling()和floor()。这些函数返回一个整数,如果它是通过一个精确数字类型的参数,如其中的一个INT类型或DECIMAL。这意味着,例如,如下CREATE TABLE语句失败与错误,如下所示:

MySQL的&#62;CREATE TABLE t (c FLOAT) PARTITION BY LIST( FLOOR(c) )(-&#62;PARTITION p0 VALUES IN (1,3,5),-&#62;PARTITION p1 VALUES IN (2,4,6)-&#62;);错误1490(hy000):分区函数返回类型错误

与周extract()函数说明符。通过返回的值EXTRACT()功能,使用时EXTRACT(WEEK FROM col),取决于你的价值default_week_format系统变量。for this reason,EXTRACT()是不允许一个分区函数时指定单位。(错误# 54483)

看到部分可以声明为任意类型,“数学函数”,关于这些函数的返回类型的更多信息,以及11.2节,“数字类型”