对于用户来说,分区表是一个独立的逻辑表,但是底层由多个物理子表组成。实现分区的代码实际上是对一组底层表的句柄对象(Handler Object)的封装,对于分区表的请求,都会通过句柄对象转化成对存储引擎的接口调用。
MySQL实现分区表的方式——对底层表的封装——意味着索引也是按照分区的子表定义的,而没有全局索引。
MySQL在创建表时使用PARTITION BY子句定义每个分区存放的数据。在执行查询的时候,优化器根据分区定义过滤那些没有我们需要数据的分区,这样查询就无须扫描所有分区——只需要查找包含需要数据的分区就可以了。
分区的一个主要目的就是将数据按照一个较粗的粒度分在不同的表中。这样做可以将相关的数据存放在一起,另外,如果想一次批量删除整个分区的数据也会变得很方便。
在下面的场景中,分区可以起大很大的作用:
分区表本身也有一些限制,其中比较重要的几点:
分区表上的操作按照下面的操作逻辑进行:
虽然每个操作都会“先打开并锁住所有的底层表”,但这并不是说分区表在处理过程中是锁住全表的。如果存储引擎能够自己实现行级锁,例如InnoDB,则会在分区层释放对应表锁。这个加锁和解锁过程与普通InnoDB上的查询类似。
MySQL支持多种分区表。最多的是根据范围进行分区,每个分区存储落在某个范围的记录,分表表达式可以是列,也可以是包含列的表达式。还支持键值、哈希和列表分区,不过很少用到。
为了保证大数据量的可扩展性,一般有以下两个策略:
全量扫描数据,不要任何索引。
可以使用简单的分区方式存放表,不要任何索引,根据分区的规则大致定位需要的数据位置。只要能够使用WHERE条件,将需要的数据限制在少数分区中,则效率是很高的。使用该策略假设不用将数据完全放入内存中,同时还假设需要的数据全部在磁盘上,因为内存相对较小,数据很快会被挤出内存,所以缓存起不来任何作用。适用于以正常的方式访问大量数据的时候。警告:必须将查询需要扫描的分区个数限制在一个很小的数量。
索引数据,并分离热点。
如果数据又明显的“热点”,而且除了这部分数据,其他数据很少被访问到,那么可以将这部分热点数据单独放在一个分区中,让这个分区能够有机会都缓存中内存中。这样查询就可以只访问一个很小的分区表,能够使用索引,也能够有效的使用缓存。
上面介绍的分区策略都基于两个非常重要的假设:查询都能够过滤(prunning)掉很大额外的分区、分区本身并不会带来很多额外的代价。而事实证明,这两个假设在某些场景下会有问题,下面介绍一些可能会遇到的问题。
NULL值会使分区过滤无效
关于分区表一个容易让人误解的地方就是分区的表达式的值可以是NULL:第一个分区是一个特殊分区。如果第一个分区非常大,特别是当使用“全量扫描数据,不要任何索引”的策略时,代价会非常大,而且扫描两个分区来查找列也不是我们使用分区表的初衷。为了避免这种情况,可以创建一个“无用”的第一分区。
分区列和索引列不匹配
如果定义的分区列和索引列不匹配,会导致查询无法进行分区过滤。
选择分区的成本可能很高
如范围分区。
打开或锁住所有底层表的成本可能很高
当查询访问分区表的时候,MySQL需要打开并锁住所有的底层表,这是分区表的另一个开销。这个操作在分区过滤之前发生,所以无法通过分区过滤降低此开销,并且该开销也和分区类型无关,会影响所有的查询。
维护分区的成本可能很高
某些分区维护操作速度可能很慢,例如重组分区或者类似ALTER语句的操作:这类操作需要复制数据。重组分区的原理与ALTER类似,先创建一个临时的分区,然后将数据复制到其中,最后再删除原分区。
其他一些限制:
原文:https://www.cnblogs.com/bGpi/p/15070447.html