参考官方文档:https://dev.mysql.com/doc/refman/5.7/en/partitioning-selection.html
MySQL 5.7支持显式选择分区和子分区,在执行语句时,应检查与给定WHERE条件匹配的行。 分区选择类似于分区修剪,因为只检查特定分区的匹配,但在两个关键方面有所不同:
- 要检查的分区由语句的颁发者指定,这与分区修剪不同,后者是自动的。
- 分区修剪仅适用于查询,而查询和许多DML语句都支持显式选择分区。
此处列出了支持显式分区选择的SQL语句:
- SELECT
- DELETE
- INSERT
- REPLACE
- UPDATE
- LOAD DATA
- LOAD XML
本节的其余部分讨论了显式选择分区,因为它通常适用于刚刚列出的语句,并提供了一些示例。
使用PARTITION选项实现显式分区选择。 对于所有受支持的语句,此选项使用此处显示的语法:
PARTITION (partition_names)
partition_names: partition_name, ...
此选项始终跟随分区所属的表的名称。 partition_names是要使用的分区或子分区的逗号分隔列表。 此列表中的每个名称必须是指定表的现有分区或子分区的名称; 如果找不到任何分区或子分区,则语句将失败并显示错误(分区'partition_name'不存在)。 partition_names中命名的分区和子分区可以按任何顺序列出,并且可以重叠。
使用PARTITION选项时,仅检查列出的分区和子分区的匹配行。 可以在SELECT语句中使用此选项来确定哪些行属于给定分区。 考虑一个名为employees的分区表,使用此处显示的语句创建和填充:
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> SELECT * FROM employees PARTITION (p1);
结果与查询SELECT * FROM employees WHERE id BETWEEN 5 AND 9获得的结果相同。
要从多个分区获取行,请将它们的名称作为逗号分隔的列表提供。 例如,SELECT * FROM employees PARTITION(p1,p2)返回分区p1和p2中的所有行,同时从其余分区中排除行。
可以使用PARTITION选项重写针对分区表的任何有效查询,以将结果限制为一个或多个所需分区。 您可以使用WHERE条件,ORDER BY和LIMIT选项等。 您还可以将聚合函数与HAVING和GROUP BY选项一起使用。 以下每个查询在以前定义的employees表上运行时生成有效结果:
mysql> SELECT * FROM employees PARTITION (p0, p2)
-> WHERE lname LIKE 'S%';
mysql> SELECT id, CONCAT(fname, ' ', lname) AS name
-> FROM employees PARTITION (p0) ORDER BY
mysql> SELECT store_id, COUNT(department_id) AS c
-> FROM employees PARTITION (p1,p2,p3)
-> GROUP BY store_id HAVING c > 4;
使用分区选择的语句可以与使用MySQL 5.7中支持的任何分区类型的表一起使用。 当使用[LINEAR] HASH或[LINEAR] KEY分区创建表并且未指定分区的名称时,MySQL会自动命名分区p0,p1,p2,...,pN-1,其中N是数字 分区。 对于未明确命名的子分区,MySQL会自动为每个分区pX中的子分区分配名称pXsp0,pXsp1,pXsp2,...,pXspM-1,其中M是子分区的数量。 在针对此表执行SELECT(或允许显式分区选择的其他SQL语句)时,可以在PARTITION选项中使用这些生成的名称
您还可以在INSERT ... SELECT语句的SELECT部分中使用PARTITION选项,如下所示:
INSERT INTO employees_copy -> SELECT * FROM employees PARTITION (p2);
分区选择也可以与连接一起使用。 假设我们使用此处显示的语句创建并填充两个表:
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');
您可以从连接中的任何表中显式选择分区(或子分区,或两者)。 (用于从给定表中选择分区的PARTITION选项紧跟在表的名称之前,在所有其他选项之前,包括任何表别名。)例如:
mysql> SELECT -> e.id AS 'Employee ID', CONCAT(e.fname, ' ', e.lname) AS Name,
-> s.city AS City, d.name AS department
-> FROM employees AS e
-> JOIN stores PARTITION (p1) AS s ON e.store_id=s.id
-> JOIN departments PARTITION (p0) AS d ON e.department_id=d.id -> ORDER BY e.lname;
当PARTITION选项与DELETE语句一起使用时,只检查随该选项列出的那些分区(和子分区,如果有的话)。 忽略任何其他分区,如下所示:
mysql> SELECT * FROM employees WHERE fname LIKE 'j%';
mysql> DELETE FROM employees PARTITION (p0, p1)
-> WHERE fname LIKE 'j%';
mysql> SELECT * FROM employees WHERE fname LIKE 'j%';
仅删除了与WHERE条件匹配的分区p0和p1中的两行。 从第二次运行SELECT时的结果可以看出,表中仍有一行与WHERE条件匹配,但位于不同的分区(p2)。
使用显式分区选择的UPDATE语句的行为方式相同; 在确定要更新的行时,仅考虑PARTITION选项引用的分区中的行:
mysql> UPDATE employees PARTITION (p0)
-> SET store_id = 2 WHERE fname = 'Jill';
对于插入行的语句,行为的不同之处在于找不到合适的分区导致语句失败。 对于INSERT和REPLACE语句都是如此:
mysql> INSERT INTO employees PARTITION (p2) VALUES (20, 'Jan', 'Jones', 1, 3); ERROR 1729 (HY000): Found a row not matching the given partition set
mysql> INSERT INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 1, 3);
Query OK, 1 row affected (0.07 sec)
mysql> REPLACE INTO employees PARTITION (p0) VALUES (20, 'Jan', 'Jones', 3, 2); ERROR 1729 (HY000): Found a row not matching the given partition set
mysql> REPLACE INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 3, 2);
Query OK, 2 rows affected (0.09 sec)
对于将多行写入使用InnoDB存储引擎的分区表的语句:如果VALUES后面的列表中的任何行无法写入partition_names列表中指定的某个分区,则整个语句将失败并且不会写入任何行。 以下示例中的INSERT语句显示了这一点,重用了先前创建的employees表:
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 -> );
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); Q
uery OK, 2 rows affected (0.06 sec) Records: 2 Duplicates: 0 Warnings: 0
对于写入多行的INSERT语句和REPLACE语句,前面都是如此。
在MySQL 5.7.1及更高版本中,对于使用提供自动分区的存储引擎(例如NDB)的表,禁用分区选择。 (BUG 14827952)