主键和二级索引
主表
指使用CREATE TABLE语句创建的表对象。也是索引对象所依赖的表(即CREATE INDEX语句中ON子句所指定的表)
主键
OceanBase的每一张表都有主键,并在内部以主键为序组织数据。如果在创建用户表时不显式指定主键,系统会自动为表生成隐藏主键,隐藏主键不可被查询
索引(索引表)
指使用CREATE INDEX语句创建的索引对象。有时为了便于大家理解,也会把索引对象类比为一个表对象,即索引表
传统“非分区表”中主表和索引的关系
传统的“非”分区表中,主表和索引的对应关系:
主表的所有数据都保存在一个完整的数据结构中,主表上的每一个索引也对应一个完整的数据结构(比如最常见的B+ Tree),主表的数据结构和索引的数据结构之间是一对一的关系,如下图所展示,在employee表中,以emp_id创建的索引:
局部索引与全局索引
当分区表出现之后,情况发生了变化:主表的数据按照分区键(Partitioning Key)的值被分成了多个分区,每个分区都是独立的数据结构,分区之间的数据没有交集。这样一来,索引所依赖的单一数据结构不复存在,那索引需要如何应对呢?——这就引入了“局部索引”和“全局索引”两个概念。
局部索引
局部索引又名分区索引,创建索引的分区关键字是LOCAL,分区键等同于表的分区键,分区数等同于表的分区数,总之,局部索引的分区机制和表的分区机制一样
全局索引
全局索引的创建规则是在索引属性中指定GLOBAL关键字,与局部索引相比,全局索引最大的特点是全局索引的分区规则跟表分区是相互独立的,全局索引允许指定自己的分区规则和分区个数,不一定需要跟表分区规则保持一致
局部索引
分区表的局部索引和非分区表的索引类似,索引的数据结构还是和主表的数据结构保持一对一的关系,但由于主表已经做了分区,主表的“每一个分区”都会有自己单独的索引数据结构。局部索引的结构如下图所示:
全局索引-全局非分区索引
分区表的全局索引不再和主表的分区保持一对一的关系,而是将所有主表分区的数据合成一个整体来建立全局索引。更进一步,全局索引可以定义自己独立的数据分布模式,既可以选择非分区模式也可以选择分区模式 :
全局非分区索引(Global Non-Partitioned Index)
全局分区索引(Global Partitioned Index)
全局索引-全局分区索引
分区表的全局索引不再和主表的分区保持一对一的关系,而是将所有主表分区的数据合成一个整体来建立全局索引。更进一步,全局索引可以定义自己独立的数据分布模式,既可以选择非分区模式也可以选择分区模式 :
全局非分区索引(Global Non-Partitioned Index)
全局分区索引(Global Partitioned Index)
功能需求:在表的‘分区键无关’的字段上建唯一索引
局部索引在“索引键没有包含主表所有的分区键字段”的情况下,此时索引键值对应的索引数据在所有分区中都可能存在。如下图,employee按照emp_id做了分区,但同时想利用局部索引建立关于emp_name的唯一约束是无法实现的。
由于某索引键值在所有分区的局部索引上都可能存在,索引扫描必须在所有的分区上都做一遍,以免造成数据遗漏。这会导致索引扫描效率低下,并且会在全局范围内造成CPU和IO资源的浪费
全局非分区索引与全局分区索引的比较
全局索引的分区键一定是索引键的前缀
全局非分区索引 :
此时索引的结构和“非分区”表没有区别,只有一个完整的索引树,自然保证唯一性。并且只有一个完整的索引树,自然没有多分区扫描的问题
全局分区索引
数据只可能落在一个固定的索引分区中,因此每个索引分区内保证唯一性约束,就能在全表范围内保证唯一性约束全局索引能保证某一个索引键的数据只落在一个固定的索引分区中 ,所以无论是针对固定键值的索引扫描,还是针对一个键值范围的索引扫描,都可以直接定位出需要扫描的一个或者几个分区
局部索引与全局索引的执行计划的比较
局部索引
create table t_p_hash (c1 varchar(20),c2 int, c3 varchar(20)) partition by hash(c2) partitions 3; create index idx_t_p_hash_c1 on t_p_hash (c1) local; create index idx_t_p_hash_c3 on t_p_hash (c3) local; explain extended select c1,c2 from t_p_hash where c3='100';
局部索引与全局索引的执行计划的比较
全局索引
create table t_p_key (c1 varchar(20),c2 int,c3 varchar(20)) partition by key (c2) partitions 3; create unique index idx_t_p_key_c3_g on t_p_key (c3) global partition by key (c3) partitions 3; explain extended select c1,c2 from t_p_key where c3='66';
局部索引与全局索引的取舍
如果查询条件里“包含完整的分区键”,使用本地索引是最高效的
如果需要“不包含完整分区键”的唯一约束:
用全局索引
或者本地索引,且需要索引列上必须带上表的分区键
其他情况,case by case:
通常来说,全局索引能为高频且精准命中的查询(比如单记录查询)提速并减少IO;对范围查询则不一定哪种索引效果更好
不能忽视全局索引在DML语句中引入的额外开销:数据更新时带来的跨机分布式事务,事务的数据量越大则分布式事务越复杂
如果数据量较大,或者容易出现索引热点,可考虑创建全局分区索引