称为 分区修剪 的优化基于一个相对简单的概念,可以描述为 “不扫描不可能存在匹配值的分区”。假设通过以下语句创建分区表 t1
CREATE TABLE t1 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY RANGE( region_code ) (
PARTITION p0 VALUES LESS THAN (64),
PARTITION p1 VALUES LESS THAN (128),
PARTITION p2 VALUES LESS THAN (192),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
假设您希望从如下 SELECT
语句中获取结果
SELECT fname, lname, region_code, dob
FROM t1
WHERE region_code > 125 AND region_code < 130;
很容易看出,应该返回的所有行都不在分区 p0
或 p3
中;也就是说,我们只需要搜索分区 p1
和 p2
即可找到匹配的行。通过限制搜索范围,与扫描表中的所有分区相比,可以花费更少的时间和精力来查找匹配的行。这种““剪除”” 不需要的分区的操作称为 修剪。当优化器可以在执行此查询时利用分区修剪时,查询的执行速度可以比针对包含相同列定义和数据的非分区表的相同查询快一个数量级。
只要 WHERE
条件可以简化为以下两种情况之一,优化器就可以执行修剪
partition_column
=constant
partition_column
IN (constant1
,constant2
, ...,constantN
)
在第一种情况下,优化器只需计算给定值的分区表达式,确定包含该值的分区,然后仅扫描此分区。在许多情况下,等号可以用另一个算术比较运算符代替,包括 <
、>
、<=
、>=
和 <>
。在 WHERE
子句中使用 BETWEEN
的某些查询也可以利用分区修剪。请参阅本节后面的示例。
在第二种情况下,优化器计算列表中每个值的分区表达式,创建一个匹配分区列表,然后仅扫描此分区列表中的分区。
SELECT
、DELETE
和 UPDATE
语句支持分区修剪。INSERT
语句在每个插入的行中也只访问一个分区;即使对于通过 HASH
或 KEY
分区的表也是如此,尽管这在 EXPLAIN
的输出中当前未显示。
修剪也可以应用于短范围,优化器可以将这些范围转换为等效的值列表。例如,在前面的示例中,WHERE
子句可以转换为 WHERE region_code IN (126, 127, 128, 129)
。然后,优化器可以确定列表中的前两个值位于分区 p1
中,其余两个值位于分区 p2
中,并且其他分区不包含相关值,因此无需搜索匹配的行。
对于使用 RANGE COLUMNS
或 LIST COLUMNS
分区的表,优化器还可以对涉及多列上前述类型比较的 WHERE
条件执行修剪。
只要分区表达式由可以简化为一组等式的等式或范围组成,或者当分区表达式表示递增或递减关系时,就可以应用这种类型的优化。当分区表达式使用 YEAR()
或 TO_DAYS()
函数时,也可以将修剪应用于在 DATE
或 DATETIME
列上分区的表。当分区表达式使用 TO_SECONDS()
函数时,也可以将修剪应用于此类表。
假设使用此处所示的语句创建在 DATE
列上分区的表 t2
CREATE TABLE t2 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY RANGE( YEAR(dob) ) (
PARTITION d0 VALUES LESS THAN (1970),
PARTITION d1 VALUES LESS THAN (1975),
PARTITION d2 VALUES LESS THAN (1980),
PARTITION d3 VALUES LESS THAN (1985),
PARTITION d4 VALUES LESS THAN (1990),
PARTITION d5 VALUES LESS THAN (2000),
PARTITION d6 VALUES LESS THAN (2005),
PARTITION d7 VALUES LESS THAN 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'
在最后一种情况下,优化器还可以执行以下操作
查找包含范围低端的分区.
YEAR('1984-06-21')
产生值1984
,该值位于分区d3
中。查找包含范围高端的分区.
YEAR('1999-06-21')
的计算结果为1999
,该值位于分区d5
中。仅扫描这两个分区以及可能位于它们之间的任何分区.
在这种情况下,这意味着仅扫描分区
d3
、d4
和d5
。可以安全地忽略其余分区(并且会被忽略)。
在针对分区表的语句的 WHERE
条件中引用的无效 DATE
和 DATETIME
值将被视为 NULL
。这意味着诸如 SELECT * FROM
之类的查询不会返回任何值(请参阅错误 #40972)。partitioned_table
WHERE date_column
< '2008-12-00'
到目前为止,我们只看了使用 RANGE
分区的示例,但修剪也可以应用于其他分区类型。
考虑一个按 LIST
分区的表,其中分区表达式是递增或递减的,例如此处所示的表 t3
。(在本例中,为了简洁起见,我们假设 region_code
列的值限制在 1 到 10 之间,包括 1 和 10。)
CREATE TABLE t3 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY LIST(region_code) (
PARTITION r0 VALUES IN (1, 3),
PARTITION r1 VALUES IN (2, 5, 8),
PARTITION r2 VALUES IN (4, 9),
PARTITION r3 VALUES IN (6, 7, 10)
);
对于诸如 SELECT * FROM t3 WHERE region_code BETWEEN 1 AND 3
之类的语句,优化器会确定值 1、2 和 3 位于哪些分区中(r0
和 r1
),并跳过其余分区(r2
和 r3
)。
对于通过 HASH
或 [LINEAR] KEY
分区的表,如果 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
子句转换为 WHERE region_code IN (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
或 [LINEAR] KEY
分区时,修剪只能用于整数列。例如,以下语句不能使用修剪,因为 dob
是 DATE
列
SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';
但是,如果表在 INT
列中存储年份值,则可以使用 WHERE year_col >= 2001 AND year_col <= 2005
修剪查询。
如果表使用提供自动分区的存储引擎(例如 MySQL 集群使用的 NDB
存储引擎),则如果对这些表进行显式分区,则可以对其进行修剪。