全局索引 
=========================



全局索引的创建规则是在索引属性中指定 GLOBAL 关键字。与局部索引相比，全局索引最大的特点是全局索引的分区规则跟表分区是相互独立的，全局索引允许指定自己的分区规则和分区个数，不一定需要跟表分区规则保持一致。

示例如下：

```sql
obclient> CREATE TABLE t1(a int PRIMARY KEY, b int, c int) PARTITION BY hash(a) partitions 5;

obclient> CREATE INDEX gkey ON t1(b) GLOBAL PARTITION BY range(b) (
  partition p0 VALUES less than (1), 
  partition p1 VALUES less than (2), 
  partition p2 VALUES less than (3)
);
```



全局索引的分区键一定是索引键本身，因此在使用全局索引的过程中就会指定索引分区键的查询条件，我们可以针对索引的分区规则进行分区裁剪，在查询到索引键值后可以利用索引表中存储的主键信息计算出主表的分区位置，进而对主表也能进行快速的分区定位，避免扫描主表的所有分区，因此对于无法指定主表分区键的查询而言，全局索引在一定条件下能够加速查询的检索效率。

示例如下：

```sql
obclient> EXPLAIN SELECT /*+index(t1 gkey)*/ * FROM t1 WHERE b=1\G
*************************** 1. row ***************************
Query Plan: ==========================================
|ID|OPERATOR    |NAME    |EST. ROWS|COST |
------------------------------------------
|0 |TABLE LOOKUP|T1      |4950     |38645|
|1 | TABLE SCAN |T1(GKEY)|4950     |1115 |
==========================================

Outputs & filters:
-------------------------------------
  0 - output([T1.A], [T1.B], [T1.C]), filter(nil),
      partitions(p[0-4])
  1 - output([T1.A]), filter(nil),
      access([T1.A]), partitions(p1)
```



对于上述查询，首先通过 `where` 条件中的 `b=1` 条件裁剪出全局索引的分区 p1，然后对全局索引进行 `table scan` 操作以得到对应的主键。利用 `table lookup` 算子对主表进行精确的分区扫描以避免扫描主表的所有分区。

在 OceanBase 数据库中，如果索引属性关键字没有指定，那么默认的索引属性是 GLOBAL 属性，即创建的索引是全局索引，并且索引表只有一个分区。

如果主表没有指定分区键或者指定的分区数为 1，那么主表也只有一个分区，这个时候，全局索引的数据和主表数据的物理位置是相互绑定在一起的，无论是迁移还是副本 Leader 发生切换，它们都是作为一个整体进行变换，不会存在中间状态。如果全局索引的分区规则和主表的分区规则相同并且分区数相同，这时推荐创建一个局部索引。 一方面是因为全局索引的维护代价更大；另一方面是因为全局索引无法保证和主表分区的物理位置相同，除非将其和主表指定在一个表组中。
