一、分区表

1. 什么是分区表?

  对用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成(所以索引也是按照分区的子表定义的,而没有全局索引)。实现分区的代码实际上是对一组底层表的句柄对象的封装。对分区表的请求,都会通过句柄对象转化成对存储引擎的接口调用。

在创建表时,使用partition by子句定义每个分区存放的数据。在执行查询的时候,优化器会根据分区定义过滤那些没有我们需要的数据的分区。

  分区的一个主要目的是将数据按照一个较粗的粒度分布在不同的表中,这样可以将相关的数据存放在一起,如果想一次批量删除整个分区的数据也会变得很方便。

2. 分区表发挥大作用的场景:

(1)表非常大以至于无法全部都放在内存中,或者只在表的最后部分有热点数据,其他均是历史数据。

(2)分区表的数据更容易维护。

(3)分区表的数据可以分布在不同的物理设备上。

(4)可以使用分区表来避免某些特殊的瓶颈,例如InnoDB单个索引的互斥访问。

(5)如果需要,还可以备份和恢复独立的分区,这在非常大的数据集的场景下效果非常好。

3. 分区表的限制:

(1)一个表最多只能有1024个分区。

(2)在MySQL5.1中,分区表达式必须是整数,或者是返回整数的表达式。在MySQL5.5中,某些场景中可以直接使用列来进行分区。

(3)如果分区字段中有主键或者唯一索引的列,那么所有主键列和唯一索引列都必须包含进来。

(4)分区表中无法使用外键约束。

(5)所有分区都必须使用相同的存储引擎。

(6)分区函数中可以使用的函数和表达式也有一些限制。

(7)某些存储引擎不支持分区。

(8)对于MyISAM表,使用分区表时需要打开更多的文件描述符。

4. 分区表的原理:

  存储引擎管理分区的各个底层表和管理普通表一样(所有的底层表都必须使用相同的存储引擎),分区表的索引只是在各个底层表上各自加上一个完全相同的索引。

  在分区表上的查询操作都需要分区层首先打开并锁住所有的底层表,然后确定需要操作的分区,最后再采取相应操作。

5. 分区表的类型:

支持范围、键值、哈希、列表分区。其中有些还支持子分区,通过子分区可以将数据切成多个小片,大大降低互斥量的竞争问题。

  分区表达式可以是列,也可以是列的表达式,可以使用各种函数,但是返回的值要是一个确定的整数;分区表达式不能是一个常数。

6. 如何使用分区表:

  分区不需要精确定位每条数据的位置,所以无须额外的数据结构记录每个分区有哪些数据,代价非常低,只需要一个简单的表达式就可以表达每个分区存放的是什么数据。

保证大量数据可扩展性的两个策略:

(1)全量扫描数据,不要任何索引。

(2)索引数据,并分离热点。

7. 什么情况下会出现问题:

(1)NULL值会使分区过滤无效

  分区表达式的值可以是NULL,对应的记录会存放到第一个分区中。例如,如果按partition by range year(order_date)分区,那么所有order_date为NULL或是一个非法值的时候,记录都会被放到第一个分区。查询某个范围的数据记录时MySQL会检查包含第一个分区在内的两个分区,如果第一个分区非常大的话代价会很大。

解决方法:

<1> 创建一个没用的分区。例如上面的例子可以使用partition p_nulls values less than (0)来创建第一个分区。

<2> 在MySQL5.5之后可以直接使用列本身而不是基于列的函数进行分区:partition by range columns (order_date)。

(2)分区列和索引列不匹配

  如果定义的索引列和分区列不匹配,会导致查询无法进行分区过滤。

(3)选择分区的成本可能很高

  范围分区找到目标分区服务器需要扫描所有的分区定义列表,随着分区数增长,成本会越来越高。在应用开发中应该限制分区数量,一般100左右已经够用了。其他分区类型则没有这个问题。

(4)打开并锁住所有底层表的成本可能很高

  当查询访问分区表的时候,MySQL需要打开并锁住所有的底层表,这个操作在分区过滤之前发生,所以无法通过分区过滤降低此开销,并且该开销和分区类型无关,会影响所有查询。这对一些本身操作非常快的查询会带来明显的额外开销。

解决方法:

  使用批量操作的方式来降低单个操作的此类开销,例如使用批量插入、一次删除多行数据,等等。

(5)维护分区的成本可能很高

  重组分区或类似alter语句的操作,需要复制数据。

8. 查询优化:

(1)在where条件中带入分区列,即使看似多余,这样优化器通过分区过滤可以让查询扫描更少的数据。可以使用explain partitions观察优化器是否执行了分区过滤。

(2)MySQL只能在使用分区列本身进行比较时才能过滤分区,而不能根据基于分区列的表达式的值去过滤分区,即使这个表达式就是分区表达式也不行。

(3)若分区表是关联操作的第二张表,且关联条件是分区键,MySQL就只会在对应的分区里匹配行。但explain无法显示这种情况下的分区过滤,因为这是运行时的分区过滤,而不是查询优化阶段的。

 

二、合并表

1. 什么是合并表?

  合并表是一种早期的、简单的分区实现,和分区表相比有一些不同的限制,并且缺乏优化。分区表严格来说是一个逻辑上的概念,用户无法访问底层的各个分区,但是合并表允许用户单独访问各个字表。分区表和优化器的结合更紧密,这也是未来发展的趋势,而合并表是一种即将被淘汰的技术。

  合并表其实就是使用一个merge存储引擎逻辑表来封装多个myisam存储引擎物理子表,逻辑表和子表的结构完全相同(包括字段、索引等)。删除一个合并表,它的子表不会受任何影响,而如果删除其中一个子表则可能会有不同的后果,这要视操作系统而定。

2. 合并表的一些限制和行为:

(1)在使用create语句创建一个合并表的时候,并不会检查各个子表的兼容性。如果子表的定义稍有不同,那么MySQL就可能创建出一个无法使用的合并表。

(2)在合并表上无法使用replace语法,无法使用自增字段。

(3)如果一个查询访问合并表,那么它需要访问所有子表,这有时候会导致很差的性能,应该对子表的个数进行限制。

3. 分区所不能提供的特性:

(1)一个MyISAM表可以是多个合并表的子表。

(2)可以通过直接复制.frm、.MYI、.MYD文件来实现在不同的服务器之间复制各个子表。

(3)在合并表中可以很容易地添加新的子表,直接修改合并表的定义就可以了。

(4)可以创建一个合并表,让它只包含需要的数据。

(5)如果相对某个子表做备份、恢复、修改、修复或者别的操作时,可以先将其从合并表中删除,操作结束后再将其加回去。

(6)可以使用myisampack工具来压缩所有的子表。