Android开发

MySQL 高级特性(一):数据表分区概念及机制

2021-05-14  本文已影响0人  岛上码农

当数据表过大时,通过普通的查询优化技巧已经无法大幅度提升性能,此时往往需要进行分区分表优化。分区其实是将一张逻辑上统一的表在物理上划分成了多张表。分区操作对使用者而言是一个黑盒操作,但是如果你从文件系统上看,就会看到分区数据表的实际存储方式是分开的。

MySQL 的分区的实现方式是对数据表进行一层包装,这意味着索引实际是基于每个分区定义的,而不是整张表。这个特性和 Oracle 是不同的,在 Oracle 中的索引和数据表可以使用更灵活和更复杂的方式进行分区。

MySQL 的分区通过定义 PATITION BY 子句的条件来决定数据行所属分区的归属。在执行查询的时候,查询优化器会区分所在分区,这意味着查询不会检查全部分区,而仅仅是那些包含索要查询数据所在的分区。

分区的主要目的是对数据表进行大致形式的索引和聚集。这样可以减少数据表的过大范围的访问,并可以将相关的数据行临近存储。分区的收益是显著的,尤其是对于下面的场景:

MySQL 的分区实现细节十分复杂,弄清楚是很难的,我们只需要关注它的性能即可。如果想进一步了解,可以翻阅 MySQL 手册中关于分区的部分。有了分区后,也带来了其他问题以及限制:

分区机制

如前所述,分区表实际有多个隐藏的物理存储表,这通过句柄对象呈现。我们不能直接访问分区。通常,每个分区是通过存储引擎管理的(因此要求所有分区的存储引擎相同),而数据表中的索引实际上是隐藏的物理存储表的索引。从存储引擎的角度来看,分区也是数据表。存储引擎实际并不知道数据表是独立的还是一个大的数据表的一个分区。对于分区表的操作通过如下的逻辑操作实现:

上面的有些操作支持分区过滤(即忽略无关的分区)。例如,删除一行时,服务器需要首先定位数据行位置。如果在 WHERE 条件中指定了匹配的分区表达式条件,服务器可以忽略掉不包含该行的分区。对于 UPDATE 操作也是类似,而 INSERT 操作本身就是如此,服务器会只查找需要插入的一个分区,而不是全部。

虽然分区层打开和锁定了全部分区,但并不意味着分区会保持锁定。像 InnoDB 的存储引擎,可以支持行级别的锁定,会只是分区层解除分区的锁定。这个加锁和解锁的过程和普通的 InnoDB 数据表的锁定过程类似。

分区的类型

MySQL 支持几种类型的分区,最常用的类型是范围分区——也就是针对某些列的的值或表达式按不同的范围进行分区。例如,下面的语句就是根据年份将销售数据分到不同的分区中:

CREATE TABLE sales (
  order_date DATETIME NOT NULL
  --其他列定义
) ENGINE=InnoDB PARTITION BY RANGE(YEAR(order_date)) (
  PARTITION p_2018 VALUES LESS THAN (2018),
  PARTITION p_2019 VALUES LESS THAN (2019),
  PARTITION p_2020 VALUES LESS THAN (2020),
  PARTITION p_other VALUES LESS THAN MAXVALUE);

可以在分区子句中使用多种函数。最主要的要求是必须返回一个非常量的,确定的整数。在上面的例子中使用的是 YEAR 函数,也可以使用其他函数,例如 TO_DAYS()。使用时间间隔进行分区是基于日期数据的常用方式。

MySQL 也支持键,哈希以及列表的分区方法,有些还支持子分区(实际很少用)。在 MySQL 5.5以后,可u一使用 RANGE COLUMNS 的分区类型直接按基于日期的列进行分区,而不需要使用函数将日期转换为整数。
其他常见的分区技巧包括:

本篇介绍了 MySQL 的数据表分区的基本概念、工作机制和常用分区类型,下一篇将介绍如何使用分区。

上一篇下一篇

猜你喜欢

热点阅读