Android开发

MySQL 高级特性(三):数据表分区的应用与合并表简介

2022-07-08  本文已影响0人  岛上码农

前面两篇讲述了数据表分区的概念,特性及可能的缺陷,本篇介绍数据表分区的应用。

优化查询

分区引入了的新的方式来优化查询(当然也会有一些坑)。最大的特性是优化器可以使用分区函数过滤掉无关的分区。这个特性就像是一个粗粒度的索引,使得查询时可以访问更少的数据。

因此在 WHERE 子句中指定分区条件十分重要,即便有可能是多余的。有了这个条件,优化器就可以过滤掉不需要的分区。如果不这么做的话,查询执行器引擎不得不访问数据表的全部分区,这会导致极其慢的查询速度。

可以通过 EXPLAIN PARTITION 指令来查看优化器是否过滤掉了分区,以下面的例子为例:

EXPLAIN PARTITIONS SELECT * FROM sales;
id: 1
select_type: SIMPLE
partitions: p_2019,p_2020,p_2021
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 3
Extra: 

如上面所见,这种情况会访问全部的分区,而如果在 WHERE 条件增加约束条件:

EXPLAIN PARTITIONS SELECT * FROM sales_by_day WHERE day > '2020-01-01';
id: 1
select_type: SIMPLE
table: sales_by_day
partitions: p_2020,p_2021

优化器对分区的优化很到位,将范围值转换为离散的值并会针对它们决定要查询哪些分区。然而,它并不是万能的,下面的查询看起来是可以优化的,实际却不会:

EXPLAIN PARTITIONS SELECT * FROM sales_by_day WHERE YEAR(day) > 2020;
id: 1
select_type: SIMPLE
table: sales_by_day
partitions: p_2019, p_2020,p_2021

MySQL 只能在分区函数对应的列上进行分区过滤优化,而不能基于一个表达式,即便是表达式的结果看起来是一样的。这和索引不能用在表达式的参数里是一样的道理。上面的查询可以用下面等效的方式进行优化:

EXPLAIN PARTITIONS SELECT * FROM sales_by_day 
WHERE day BETWEEN '2020-01-01' AND '2020-12-31';
id: 1
select_type: SIMPLE
table: sales_by_day
partitions: p_2020

由于 WHERE 条件直接引用了分区列的值,而不是表达式,优化器可以进行分区优化。这个特性的首要原则是我们可以使用表达式进行分区,但必须依据分区列进行搜索查询。

在查询过程中,优化器也足够聪明地进行分区优化。例如,如果分区表在联合查询的第二张表中,而联合查询的条件是分区键,那么 MySQL 会只在关联的分区中查找数据行(但 EXPLAIN 不会显示优化结果,这是因为这是在运行中优化的,而不是查询优化期)。

合并表

合并表的更早的、更简单的分区,存在不同的限制并且优化手段更少。由于数据表分区是处于严格的抽象层,并且不允许直接访问分区的物理隐藏表。而合并表则允许我们从合并的表中单独访问隐藏的物理表。随着未来分区的进一步集成化和优化器的改进,合并表很可能被废弃甚至被移除。

合并表实际上就是真实物理表的一个容器。可以通过一个特殊的 UNION 语法去创建多张表进行合并,下面就是一个例子:

CREATE TABLE t1(a INT NOT NULL PRIMARY KEY) ENGINE=MYISAM;
CREATE TBLE t2(a INT NOT NULL PRIMARY) ENGINE=MYISAM;
INSERT INTO t1(a) VALUES (1), (2);
INSERT INTO t2(a) VALUES(1), (2);
CREATE TABLE mrg(a INT NOT NULL PRIMARY KEY)
ENGINE=MERGE UNION=(t1, t2) INSERT_METHOD=LAST;
SELECT a FROM mrg;

执行下面的操作后,其实相当于从两张表同时取出了数据,结果是:

a
1
1
2
2

需要注意的是实际的表的字段名,数量和类型都相同,而且索引既在合并表上有,在各自的分表也有。这是创建合并表的要求。注意在每个分表在相同的列上都是相同的主键,但是合并表可以有重复的行。这是合并表的缺陷,合并表的每条数据看起来都是正常的,但合并表不会自己增加相应的约束,因此需要使用程序来约束。

INSERT_METHOD=LAST 指令告知 MySQL 会将对上一个表的插入数据同时发送到合并表中。我们只能指定 FIRST 或 LAST 操作,而且也可以直接对分表单独操作。这与分区表是不同的,分区表对数据的存储有更多的控制条件。

往合并表插入数据会同时在合并表和分区表中插入。

INSERT INTO mrg(a) VALUES(3);
SELECT a FROM t2;
a
1
2
3

合并表还有一些有趣的特性和限制,例如删除合并表或其中的一个分表。删除合并表不影响其分表,但是删除其中一个分表则根据操作系统不同而不同。例如,对于 Linux 系统,分表的文件描述符依旧保留并且数据表也存在,但只能通过合并表查询。

DROP TABLE t1, t2;
SELECT a FROM mrg;
a
1
1
2
2
3

下面是合并表的一些限制,这些需要记住,以避免踩坑:

而数据表分区则不同,所有的物理表被 MySQL 服务端隐藏了,只能通过分区表访问和控制。

上一篇下一篇

猜你喜欢

热点阅读