基于湖库一体架构,统一管理结构化、半结构化与非结构化等多模态数据,一个系统承载事务处理、实时分析与 AI 工作负载。
为什么创建的 global index(全局索引)会自动变成 local index(本地索引)?
更新时间:2024-10-17 02:07
问题一:在一张非分区表上,创建 global index(全局索引),在 ODC 中被展示成了本地索引(local index),是否非分区表上的 global index(全局索引)都会被转换为 local index(本地索引)?
-- 创建测试表 t1。
create table t1(c1 int, unique index g_idx(c1) global);
-- 通过 ODC 查看表定义的 DDL,可能会是如下结果。
CREATE TABLE `t1` (
`c1` int(11) DEFAULT NULL,
UNIQUE KEY `g_idx` (`c1`) LOCAL
)
由于 ODC 老版本存在 BUG,如果遇到的话,直接更新 ODC 到最新版本。
为什么即使 ODC 在这种情况下把索引的 global 属性改成 local 属性,也不会有任何问题?
local 索引的定义:索引必须和主表的分区方式完全相同。
global 索引的定义:可以和主表的分区方式不同或者相同。当创建一个不显式指定索引分区规则的 global index(全局索引),索引就会被默认的创建为非分区索引(只有一个分区的索引),如果主表也是非分区表(只有一个分区的表),表和索引的分区方式一致,都是单分区,那么就等价于创建了一个 local index(本地索引)也就是和主表分区方式一致的索引。所以,在非分区表上,创建一个不显式指定分区规则 global index(全局索引),其实和创建一个 local index(本地索引)是没有实质区别的。
综上论述可知非分区表上的 global index(全局索引)不会都会被转换为 local index(本地索引),因为 global index(全局索引)也可以有自己独立于主表的分区方式,例如下面这种 DDL,主表是非分区表,global index(全局索引)是分区表,那么就不能随意将 global index(全局索引) 改成 local index(本地索引),否则就会有正确性问题。
-- 建表 DDL
create table t2(c1 int, unique index g_idx(c1) global partition by hash(c1));
-- 通过 ODC 查看表定义的 DDL,可能会是如下结果:
CREATE TABLE `t2` (
`c1` int(11) DEFAULT NULL,
UNIQUE KEY `g_idx` (`c1`) BLOCK_SIZE 16384 GLOBAL
partition by hash(c1)
(partition `p0`)
)
问题二:如何通过 SQL 来判断整个 OceanBase 数据库里的哪些索引是 global 属性的,哪些是 local 属性的?
因为 global 索引不是和 MySQL 兼容的功能,冒然在 MySQL 兼容视图例如 statistics 上加字段,可能会导致 MySQL 生态工具的兼容性问题,所以 OceanBase 在 MySQL 模式下暂时还没有提供相关的字典视图,可通过内部表 __all_virtual_table(非官方提供的方案)。
在 sys 租户下查的话,可以查到所有租户的所有表的元信息,若在用户租户下查的话,可以查到当前租户的所有表的元信息。
-- 在 sys 租户下查。
select distinct(tenant_id) from oceanbase.__all_virtual_table;
输出结果如下:
+-----------+
| tenant_id |
+-----------+
| 1 |
| 1001 |
| 1002 |
+-----------+
3 rows in set (0.045 sec)
-- 在用户租户下查
select distinct(tenant_id) from oceanbase.__all_virtual_table;
输出结果如下:
+-----------+
| tenant_id |
+-----------+
| 1002 |
+-----------+
1 row in set (0.043 sec)
注意
由于内部表 __all_virtual_table 非字典视图,不保证所有字段都能够向后兼容,若遇字典视图实在查不出相应的信息,否则不推荐直接查这张表。
比如查询在用户租户下执行下面这条 SQL,就可以查出当前租户的所有 unique global index。
SELECT b.table_name data_table_name,
substr(a.table_name, 7 + instr(substr(a.table_name, 7), '_')) index_name
FROM oceanbase.__all_virtual_table a,
oceanbase.__all_virtual_table b
WHERE a.data_table_id = b.table_id
AND (a.index_type = 4
OR a.index_type = 8);
输出结果如下:
+-----------------+------------+
| data_table_name | index_name |
+-----------------+------------+
| t1 | g_idx |
| t2 | g_idx |
+-----------------+------------+
2 rows in set (0.048 sec)
SQL 语句中涉及内部表 __all_virtual_table 的字段 data_table_id 含义: data_table_id 主表和索引表都会在 __all_virtual_table 中占据一行,索引表的 data_table_id 字段就是其主表的 table_id,所以通过 a.data_table_id = b.table_id 关联主表和索引表。
另外该 SQL 语句对索引表的 table_name 做 substr,因为这张内部表里记录的索引表的 table_name 的原始信息是为 __idx_主表id_索引表名,如下所示。
SELECT
b.table_id data_table_id,
a.table_id index_table_id,
b.table_name data_table_name,
a.table_name index_name
FROM oceanbase.__all_virtual_table a,
oceanbase.__all_virtual_table b
WHERE a.data_table_id = b.table_id
AND (a.index_type = 4
OR a.index_type = 8);
输出结果如下:
+---------------+----------------+-----------------+--------------------+
| data_table_id | index_table_id | data_table_name | index_name |
+---------------+----------------+-----------------+--------------------+
| 500077 | 500078 | t1 | __idx_500077_g_idx |
| 500079 | 500080 | t2 | __idx_500079_g_idx |
+---------------+----------------+-----------------+--------------------+
2 rows in set (0.046 sec)
上述 SQL 语句中过滤条件 index_type = 4 OR a.index_type = 8 有关 index_type 的含义,可参见 github 中 ob_schema_struct 的 ObIndexType 定义部分,相应的标注如下。 
index_type = 8 的 index 应该就是普通的 unique global index,index_type = 8 的 index 应该是第一个问题中 unique local index 退化成 unique global index。
适用版本
OceanBase 数据库 V4.2.x 版本。