这个机器人回答的还是不错的,很有条理。
不过关于 __all_index
的那一段看起来犯了跟 chatgpt 一样的错误:一本正经的胡说八道。
翻遍 OB 的官网,没有看到有视图叫 __all_index
,在 OB 里也没有视图字段直接说明一个索引到底是全局索引还是本地索引。需要借助理论自己去分析判断。
理论部分
一个普通的表,其数据和索引,OB 是放在一起存储的。虽然内部会有用两个 table_id
去表示(索引的 data_table_id
= 表的 table_id
)。OB 是把他们放一起的。这个也决定了 OB 的分布式相比 TiDB (具体是 TiKV)的分布式有更好的控制能力,从而可能有更好的性能。OB 普通表的数据和索引在一起,也就在一个节点,通过索引回表访问数据的时候,不会有跨节点的请求,业务 DML 也不会人为构造分布式事务。
一个分区表,其数据有多个分区,每个分区可以有自己的索引。这个索引如果跟对应的分区在一起(也是两个 table_id
这个没关系),那就是 LOCAL 索引。如果分区表的索引跟对应的分区不在一起,那就是 GLOBAL 索引。这个 GLOBAL 索引默认是一个独立的分区。global 索引容易导致跨机请求或分布式事务,所以最佳实践是优先使用本地索引。
OB 里索引还可以再分区。一个普通表的索引如果设置了分区属性,那么就不能称之为 LOCAL 索引,其索引要跟表数据分开存放。应该就是 GLOBAL 索引。一个分区表的 GLOBAL 索引还可以再次分区,那依然是一个 GLOBAL 索引。
OB 索引如果不指定 LOCAL 或 GLOBAL 关键字,那么默认是什么类型呢?MySQL 租户里默认是 LOCAL 索引,ORACLE 租户里默认是 GLOBAL 索引。所以使用 OB 的时候,建议养成习惯,分区表创建索引的时候 都指定 LOCAL 还是 GLOBAL 。否则,ORACLE 租户一不小心就创建了一个 GLOBAL 索引。
一个普通的表创建普通的索引,尽管指定GLOBAL ,本质上还是LOCAL索引(不过 OB内部元数据里按GLOBAL 索引特点去记录)。这种写法不报语法错误,但不要这么折腾OB。普通表普通索引就LOCAL好了。普通表创建分区索引这种也不报语法错误,但实际上没啥实践意义。一个表都不用分区,索引就更没有分区的必要了。
实验
MySQL [test]> create table t1_nopart(id bigint not null, c1 varchar(50));
Query OK, 0 rows affected (0.07 sec)
MySQL [test]> create table t1_part(id bigint not null, c1 varchar(50)) partition by hash(id) partitions 2;
Query OK, 0 rows affected (0.06 sec)
MySQL [test]> create index t1_nopart_ind1 on t1_nopart(c1) ;
Query OK, 0 rows affected (0.26 sec)
MySQL [test]> create index t1_part_ind1 on t1_part(c1) ;
Query OK, 0 rows affected (0.27 sec)
MySQL [test]> create index t1_part_ind2 on t1_part(c1) local;
Query OK, 0 rows affected (0.27 sec)
MySQL [test]> create index t1_nopart_ind2 on t1_nopart(c1,id) partition by hash(id) partitions 2;
Query OK, 0 rows affected (0.27 sec)
obclient [TPCC]> create table t1_nopart(id number, c1 varchar2(50));
Query OK, 0 rows affected (0.132 sec)
obclient [TPCC]> create table t1_part(id number, c1 varchar2(50)) partition by hash(id) partitions 2;
Query OK, 0 rows affected (0.077 sec)
obclient [TPCC]> create index t1_nopart_ind1 on t1_nopart(c1);
Query OK, 0 rows affected (0.273 sec)
obclient [TPCC]> create index t1_nopart_ind2 on t1_nopart(c1,id) partition by hash(id) partitions 2;
Query OK, 0 rows affected (0.272 sec)
obclient [TPCC]> create index t1_part_ind1 on t1_part(c1) global;
Query OK, 0 rows affected (0.272 sec)
obclient [TPCC]> create index t1_part_ind2 on t1_part(c1,id) local;
Query OK, 0 rows affected (0.269 sec)
下面 SQL 是在 SYS 租户里观察这个表和索引用的。
select t1.CON_ID,t1.owner,t1.PARTITIONED tbl_partitioned,t1.table_name,t1.status,i1.table_type, i1.index_name, i1.uniqueness, i1.status, i1.partitioned idx_partitioned
from cdb_tables t1 join cdb_indexes i1 ON ( t1.owner=i1.table_owner and t1.table_name=i1.table_name)
where t1.owner in('test','TPCC') AND t1.table_name IN ('t1_part','t1_nopart')
order by t1.owner,t1.table_name,i1.index_name;
select t1.tenant_id,conv(t1.database_id,10,16) db_id_hex, conv(t1.table_id,10,16) table_id_hex, t1.table_name, t1.index_status,t1.index_type
, conv(t2.table_id,10,16) index_id_hex, t2.table_name index_name, t2.index_status,t2.index_type
from __all_virtual_table t1 left join __all_virtual_table t2 on (t1.tenant_id=t2.tenant_id and t1.table_id=t2.data_table_id)
where t1.tenant_id IN (1002, 1004) AND t1.table_name IN ('t1_part','t1_nopart')
ORDER BY t1.tenant_id, t1.table_name, index_name ;
CON_ID |
owner |
tbl_partitioned |
table_name |
status |
table_type |
index_name |
uniqueness |
status |
idx_partitioned |
1,002 |
test |
NO |
t1_nopart |
VALID |
TABLE |
t1_nopart_ind1 |
NONUNIQUE |
VALID |
NO |
1,002 |
test |
NO |
t1_nopart |
VALID |
TABLE |
t1_nopart_ind2 |
NONUNIQUE |
VALID |
YES |
1,002 |
test |
YES |
t1_part |
VALID |
TABLE |
t1_part_ind1 |
NONUNIQUE |
VALID |
NO |
1,002 |
test |
YES |
t1_part |
VALID |
TABLE |
t1_part_ind2 |
NONUNIQUE |
VALID |
YES |
1,004 |
TPCC |
NO |
T1_NOPART |
VALID |
TABLE |
T1_NOPART_IND1 |
NONUNIQUE |
VALID |
NO |
1,004 |
TPCC |
NO |
T1_NOPART |
VALID |
TABLE |
T1_NOPART_IND2 |
NONUNIQUE |
VALID |
YES |
1,004 |
TPCC |
YES |
T1_PART |
VALID |
TABLE |
T1_PART_IND1 |
NONUNIQUE |
VALID |
NO |
1,004 |
TPCC |
YES |
T1_PART |
VALID |
TABLE |
T1_PART_IND2 |
NONUNIQUE |
VALID |
YES |
tenant_id |
db_id_hex |
table_id_hex |
table_name |
index_status |
index_type |
index_id_hex |
index_name |
index_status |
index_type |
1,002 |
7BDFE |
7BE73 |
t1_nopart |
1 |
0 |
7BE74 |
__idx_507507_t1_nopart_ind1 |
2 |
1 |
1,002 |
7BDFE |
7BE73 |
t1_nopart |
1 |
0 |
7BE77 |
__idx_507507_t1_nopart_ind2 |
2 |
3 |
1,002 |
7BDFE |
7BE66 |
t1_part |
1 |
0 |
7BE6C |
__idx_507494_t1_part_ind1 |
2 |
3 |
1,002 |
7BDFE |
7BE66 |
t1_part |
1 |
0 |
7BE6F |
__idx_507494_t1_part_ind2 |
2 |
1 |
1,004 |
7A160 |
7A354 |
T1_NOPART |
1 |
0 |
7A359 |
__idx_500564_T1_NOPART_IND1 |
2 |
7 |
1,004 |
7A160 |
7A354 |
T1_NOPART |
1 |
0 |
7A360 |
__idx_500564_T1_NOPART_IND2 |
2 |
3 |
1,004 |
7A160 |
7A355 |
T1_PART |
1 |
0 |
7A35A |
__idx_500565_T1_PART_IND1 |
2 |
3 |
1,004 |
7A160 |
7A355 |
T1_PART |
1 |
0 |
7A35D |
__idx_500565_T1_PART_IND2 |
2 |
1 |
从这些内部表之间的关联关系可以印证上面的理论。内部表 __all_virtual_table
的 index_type
这个字段可能是最接近说明一个索引到底是 LOCAL 还是 GLOBAL 的,不过内部表不保证向后兼容,文档也不会说明。
太绕了。如果分析不当,欢迎指出。