mysql执行查询时候,优化器先根据分区表达式的定义来过滤无用的分区,执行sql时只需要查找包含需要的数据分区就可以了。
分区的原理?
分区表管理一组分区表和管理普通表一样,各个子表的索引也是上加了一个人完全相同的索引,从存储引擎来看,子表和一个独立的普通表没有任何区别,以下大家来看看当执行以下命令的时候mysql如何操作分区表的:
- select:查询时,分区层打开并锁住所有子表,优化器先根据分区表达式过滤不需要的分区,然后调用存储引擎访问各个目标分区。
- insert:写入时,分区层打开并锁住所有子表,根据分区表达式确认存放数据的分区是哪一个,再去指定分区插入记录。
- delete:删除也是一样,还是先锁住所有分区,根据分区表达式确认数据在哪一个分区,再去那个分区删除记录。
- update:更新时相对复杂一点,分区层打开并锁住所有子表,先根据分区表达式确认数据在哪一个分区,然后先取出数据并更新,再判断更新后的数据应该存放哪个分区,最后对目标分区写入数据,最后一步要对原始数据的分区表进行删除操作。
分区类型有哪些?
- 范围分区:使用partitionbyrange(列的表达式)来表示,使用最多的分区表类型,每个分区存储某个范围内的数据,比如:
- 列表分区:使用partitionbylist(列的表达式)按离散值集合分区,这种分区类型类似于范围分区,例如:
- 哈希分区:使用partitionbyhash(列的表达式),按表达式的hashcode取模后分布到指定的区域,同理:
分区查询优化?
分区数据显而易见的好处是数据分块管理,大表拆小表,这样在操作数据的时候可以预先过滤掉不必要的数据,尽量控制在一个较小的数据区来查询数据。一个很重要的意见是:尽量在where条件中带入分区列查询,如果没有mysql就会扫描所有分区,大家可以使用expainpatitions来查看sql语句是否使用了分区过滤,如:
explainpartitionsselect*fromtuser
结果显示扫描的所有分区,大家再加上where条件:
explainpartitionsSELECT*fromtuserwherecid=2000
结果显示只扫描了一个分区。
为什么要使用数据分区?
- 表数据非常大后使用索引的代价过大、表数据呈现明显的热点数据。
- 分区表的数据更容易维护,可以单独的针对子表进行优化和修复工作,也可以操作整个分区数据。
- 分区子表的数据可以部署到不同的物理设备上,可以高效的利用多个硬件设备。
- 由于一个大表数据分散到多个子表中,这样可以避免单个索引的互斥和锁的竞争。
常见的问题有哪些?
- 一个表最多只能有1024个分区。
- 分区过多可能会导致在进行分区重组(重组会涉及到临时数据表的复制和删除)、表数据更新、分区查找的时候开销过大。
- 执行命令前mysql会锁住所有分区表,这个操作是在过滤分区和执行sql语句之前执行的,所以这个开销无法避免,最好的做法是控制分区表数量在100个以内。
- 分区表达式的返回值必须是整数。
- 分区表无法使用外键。
- null值会使分区过滤无效。
- mysql5.5以后对分区表做了大范围的优化和bug修复,所以使用这个特性之前确保你mysql高于5.5版本。
- 分区列和索引类不匹配,如果大家在某些列上创建了索引,但这些列又不参与分区,即partitionby类型(列的表达式)子句不包含这些索引列,那么mysql在扫描这些索引的时候会遍历所有分区表的索引,除非where子句使用了分区列来查询,为了避免这个问题尽量使用索引列来分区,比如: