首批通过分布式安全可靠测评,为关键业务系统打造
OceanBase 数据库支持的不可见索引介绍
更新时间:2026-05-22 08:56
本文介绍 OceanBase 数据库 MySQL 模式中不可见索引的使用方法。
适用版本
OceanBase 数据库所有版本。
不可见索引
INVISIBLE 是索引的一种状态。当索引是 INVISIBLE 状态时,SQL 优化器将不会选择该索引。创建索引时,索引默认是可见的。主键不可修改为 INVISIBLE 状态。
OceanBase 数据库中 INVISIBLE 索引与 MySQL 8.0 版本类似,不同点是 OceanBase 数据库没有 MySQL 中的 use_invisible_indexes 参数用于开启或关闭不可见索引。在 OceanBase 数据库中,可以通过 ALTER TABLE 语句修改索引是否可见。
修改索引属性的语法如下所示。
ALTER TABLE <table_name> ALTER INDEX <index_name> [ VISIBLE | INVISIBLE ];
可以通过 MySQL 的方式查询 information_schema.statistics 查询索引状态是否为 INVISIBLE。
obclient> SELECT * FROM information_schema.statistics WHERE is_visible='NO';
+---------------+--------------+------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+-----------+---------------+------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | NON_UNIQUE | INDEX_SCHEMA | INDEX_NAME | SEQ_IN_INDEX | COLUMN_NAME | COLLATION | CARDINALITY | SUB_PART | PACKED | NULLABLE | INDEX_TYPE | COMMENT | INDEX_COMMENT | IS_VISIBLE |
+---------------+--------------+------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+-----------+---------------+------------+
| def | test | fruit | 1 | test | fruit_ind | 1 | id2 | A | NULL | NULL | NULL | YES | BTREE | available | | NO |
+---------------+--------------+------------+------------+--------------+------------+--------------+-------------+-----------+-------------+----------+--------+----------+------------+-----------+---------------+------------+
1 row in set (0.03 sec)
也可以查询内部表 oceanbase.__tenant_virtual_table_index 来获得该统计信息。
obclient> SELECT * FROM oceanbase.__tenant_virtual_table_index WHERE is_visible='NO';
+------------------+-----------+--------------+--------------+-------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+------------+
| table_id | key_name | seq_in_index | table_schema | table | non_unique | index_schema | column_name | collation | cardinality | sub_part | packed | null | index_type | comment | index_comment | is_visible |
+------------------+-----------+--------------+--------------+-------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+------------+
| 1102810162709354 | fruit_ind | 1 | test | fruit | 1 | test | id2 | A | NULL | NULL | NULL | YES | BTREE | available | | NO |
+------------------+-----------+--------------+--------------+-------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+------------+
1 row in set (0.00 sec)
测试步骤
创建测试表,在 id 列创建主键,在 id2 列创建索引 fruit_ind,并向表中插入测试数据。
obclient> CREATE TABLE fruit (id int,id2 int,name varchar(20), PRIMARY KEY (id), index fruit_ind(id2)); Query OK, 0 rows affected (0.09 sec) obclient> INSERT INTO fruit VALUES (1,1,'apple'),(2,3,'banana'),(3,9,'peach'); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0));通过 WHERE 条件查询 id2 列,并显示执行计划。
此时查询计划的 NAME 列为
fruit(fruit_ind),说明查询使用索引。obclient> EXPLAIN SELECT id2 FROM fruit WHERE id2>2\G *************************** 1. row *************************** Query Plan: =============================================== |ID|OPERATOR |NAME |EST. ROWS|COST| ----------------------------------------------- |0 |TABLE SCAN|fruit(fruit_ind)|2 |37 | =============================================== Outputs & filters: ------------------------------------- 0 - output([fruit.id2]), filter(nil), access([fruit.id2]), partitions(p0) 1 row in set (0.00 sec)注意
由于数据量较小,因此只有查询索引所在的列,并且查询中具有过滤条件,才能保证查询使用索引。
将索引 fruit_ind 设置为 INVISIBLE,并再次执行步骤 2 中的查询。
此时查询计划的 NAME 列为
fruit,说明查询未使用索引,而是在 fruit 表上进行了表扫描。obclient> ALTER TABLE fruit ALTER INDEX fruit_ind INVISIBLE; Query OK, 0 rows affected (0.05 sec) obclient> EXPLAIN SELECT id2 FROM fruit WHERE id2>2\G *************************** 1. row *************************** Query Plan: ==================================== |ID|OPERATOR |NAME |EST. ROWS|COST| ------------------------------------ |0 |TABLE SCAN|fruit|1 |37 | ==================================== Outputs & filters: ------------------------------------- 0 - output([fruit.id2]), filter([fruit.id2 > 2]), access([fruit.id2]), partitions(p0) 1 row in set (0.00 sec)
注意事项
OceanBase 数据库 V1.4.7x 版本新建索引后,需要集群合并后才使得索引生效。如果使用唯一索引,需要集群合并 2 次后索引才能生效。
OceanBase 数据库 V2.X 及后续版本的索引会直接在静态的 SSTable 中构建,直接生效不需要等待合并。