分区索引简介
在数据库中,用户可以通过建立索引的方式来提升查询性能,当数据表中的数据量越来越大时,则可以通过分区的方式将数据表拆分成若干分片,利用负载均衡将数据分片打散到整个集群中来提高集群整体服务能力。在主表数据量变大的场景下,索引表的数据也可能面临同样的问题,需要进行进行拆分来提高整体服务能力。因此本文主要介绍索引分区的基本情况。
1. 名词解释
局部分区索引:创建索引的时候指定关键字LOCAL的索引为局部索引,局部索引无须指定分区规则,它的分区属性和主表一致,也会跟随主表的分区操作而发生变更;
全局分区索引:创建索引的时候指定关键字GLOBAL的索引为全局索引,全局索引可以指定分区规则进行分表,称为全局分区索引;
唯一索引:索引键值具有唯一性,用关键字unique表示;
前缀索引:不同于mysql长字符串的前缀索引,这里是指分区索引表的分区键是索引列的左前缀时,该索引称为前缀索引;比如索引表idx建立在c1,c2上,该索引表的分区键为c1,那么该索引称为前缀索引;如果该索引表的分区键为c2或者其他列,则称为非前缀索引;
非前缀索引:相对于分区前缀索引而言,如果分区索引不是前缀索引,那么称为非前缀索引;
2. 局部索引
局部索引根据分区键分为局部前缀索引和局部非前缀索引。
2.1 局部前缀索引
如果分区键是索引的左前缀,并且索引包含二级分区键,那么这个索引为局部前缀索引;局部前缀索引可以是唯一索引或者非唯一索引;
指定索引键的查询利用局部前缀索引可以唯一定位到一个索引分区;非常适合于结果集比较小,但是需要进行分区裁剪的场合;
比如:表A上有个局部索引idx(c1,c2,c3),主表根据c1进行分区,根据局部索引的特性,索引表和主表的分区方式一样,因此idx也以c1为分区键,根据定义知道这是一个局部前缀索引,当指定索引键的查询过来时,可以通过分区键c1的值定位到唯一一个索引分区,大大减少了索引分区的访问;
2.2 局部非前缀索引
如果索引表不是局部前缀索引,那就是局部非前缀索引,要么是索引表的分区键不是索引的左前缀,要么索引没有包含二级分区键;
如果分区键不是索引的子集,那么局部非前缀索引不能是唯一索引;具体原因下一节有阐述;
指定索引键的查询利用局部非前缀索引,不能定位到索引分区,需要访问所有索引分区,因此比较适合访问数据量比较大,注重并发的场景;
比如,表A上有个局部索引idx(c1,c2,c3),主表根据c4列进行分区;根据定义,这是一个局部非前缀索引,当用户查询指定索引键时,不能通过分区键定位到索引分区,因此需要访问所有的索引分区才能获得结果,这种场景下并发执行发挥重要作用;
3. 全局索引
全局索引拥有自己独立的分区定义,不需要跟主表一样;同时,全局索引表的分区也可以进行分裂和合并;
一般情况下,如果主表和全局索引的分区方式完全一样的话,除去具有唯一性的非前缀索引,其他索引建议定义成局部索引,全局索引在分区管理和维护上代价要远远大于局部索引,并且从查询代价、分区裁剪上来说,具有相同分区方式的全局索引和局部索引效果一样;
3.1 全局前缀索引
如果全局分区索引的分区键是索引键的左前缀,那么这个索引称为全局前缀索引;
全局前缀索引可以是唯一索引或者非唯一索引;
全局前缀索引只在用范围分区时有意义,对于哈希分区索引无意义;原因在于:如果是用户选择哈希分区索引,那么用户查询模式一定是指定索引键的点查询,索引键如果覆盖分区键的话,那么是不是前缀索引并无意义,都能够通过用户指定的索引键值算出索引分区;用户如果没有指定全部分区键值的话,哈希分区索引则需要访问所有的分区数据,而范围分区可以进行一定程度的分区裁剪;
3.2 全局非前缀索引
不支持全局非前缀索引;全局非前缀索引对于查询优化并没有太多意义;
比如:表A上有一个全局索引idx(c1,c2), idx通过c2进行分区;那么idx为一个非全局索引;这种情况下,只有当用户指定全部索引键值的时候才能进行分区裁剪,其他情况均需要扫描所有的索引分区;那用户没有理由不直接用c1键做分区,用c1还能做到前缀过滤进行分区裁剪;
4. 唯一索引
唯一索引可以定义为全局索引或者是局部索引;
唯一索引定义为局部索引的时候,需要满足条件: 索引键覆盖索引分区键;
比如: 表A上有个唯一索引idx(c1,c2,c3), 索引表idx按照(c1,c2)进行分区,,根据(c1,c2)进行分区能保证相同(c1,c2)一定能进入同一分区,只需要在单个分区内维护唯一性;
比如:表A上有个唯一索引idx(c1,c2,c3), 索引表idx按照(c2,c4)进行分区,索引没有覆盖分区键,我们不能通过局部索引来保证分区之间索引键的唯一性;这样的局部唯一索引不能被创建;
5. 索引创建选择策略
在创建索引的时候,需要将用户查询模式、索引管理、性能、可用性等方面的需求综合起来考虑,选择一个最合适自身业务的索引方式;这里仅仅给出一些建议:
5.1 索引创建策略
用户需要唯一索引的话,如果索引键覆盖所有分区键则可以定义成局部索引,否则需要用全局索引;
如果主表的分区键是索引的子集,则可以采用局部索引;
如果主表分区属性和索引的分区属性相同,建议采用局部索引;
如果用户比较关注索引分区管理的代价,主表分区总是不断进行分区删减时,尽量避免创建全局索引;主表分区删减操作会导致全局索引变更太大,难以恢复,而且可能会导致索引不可用;
如果用户查询总是指定所有索引分区键值,那么我们只需要在其他列上建索引,而无须包含分区键,减少维护代价和存储代价;对于不指定分区键的查询,前缀索引更合适做分区裁剪、数据量比较小的场景,前缀索引一般更适合做分区并行、数据量比较大的场景;
在进行索引分区的时候,如何选择分区方式?
(1)一般情况下,如果单个索引表的数据量太大则需要进行分区,以便查询更好的进行分区并行以及负载均衡;
(2)一般情况下,如果用户查询多为指定索引键的单点查询,从访问分区的数目和访问并发角度来说,哈希分区和范围分区的查询代价都相差不大;但是如果数据具有热点区的话,用哈希分区能更好的避免热点问题;
(3)如果用户的查询多为指定索引键的范围查询,则从访问的分区数目来说,范围索引要优于哈希索引;但从并发的角度考虑,哈希索引可以更好的利用并发查询的优势,在查询结果集很大的情况下,哈希索引的并发查询应该能有更大的性能优势;
5.2 查询时索引选择策略如果用户更注重分区裁剪的话,选择前缀索引更好,在用查询过滤条件里面指定分区前缀的值能够最大程度的进行分区裁剪,减少索引分区数据的读取;
如果用户注重吞吐量,访问的数据量比较大时,选择非前缀索引更能提高性能,可以通过分区并行的方式来解决分区键上的范围查询;局部非前缀索引可以并发访问所有的分区,但是局部前缀索引会进行分区裁剪,由少量分区处理大量的数据集合,响应时间也许会比并发查询要差一些;