全局索引

最近更新时间:2026-06-30 16:45:32

我的收藏
全局二级索引(Global Secondary Index,GSI)是 TDSQL Boundless 分区表提供的一种跨分区索引类型。与默认的 LOCAL 索引(每个分区独立存储索引数据)不同,GSI 将索引数据跨所有分区全局有序存储,使优化器可以直接通过 GSI 定位数据所在分区,无需扫描所有分区。

支持版本

适用于 TDSQL Boundless V21.6.3.0及以上版本。

注意事项

仅支持在分区表上创建全局二级索引,非分区表不支持。
全局二级索引不能作为主键索引。
存在列存节点时,暂不支持创建全局索引。
REMOVE PARTITIONING 会将全局索引变成单表的普通索引 。
包含全局索引的分区表执行 DROP PARTITION、TRUNCATE PARTITION 操作请参见 分区 DDL 与 UPDATE GLOBAL INDEXES 子句

适用场景

非分区键查询:例如一张按 user_id 哈希分区的订单表,业务还需要频繁按 order_no 查询。若使用 LOCAL 索引,按 order_no 查询会扇出到所有分区;改用 GSI 后可依据实际数据直接定位分区。
CREATE TABLE orders (
user_id BIGINT NOT NULL,
order_no VARCHAR(32) NOT NULL,
amount DECIMAL(10,2),
PRIMARY KEY (user_id, order_no),
INDEX g_idx_order_no (order_no) GLOBAL -- 全局二级索引
) PARTITION BY HASH(user_id) PARTITIONS 4;

-- 查询时优化器借助 GSI 直接定位分区,无需全分区扫描:
SELECT user_id, amount FROM orders WHERE order_no = 'NO20240601001';
全局唯一约束:例如用户表按 user_id 分区,但要求 emailphone 在全表范围内唯一。LOCAL 唯一索引只能保证分区内唯一,无法跨分区;此时使用全局唯一索引来实现。
CREATE TABLE users (
user_id BIGINT NOT NULL,
email VARCHAR(128) NOT NULL,
phone VARCHAR(20) NOT NULL,
PRIMARY KEY (user_id),
UNIQUE INDEX g_uk_email (email) GLOBAL, -- 全局唯一:email 全表唯一
UNIQUE INDEX g_uk_phone (phone) GLOBAL -- 全局唯一:phone 全表唯一
) PARTITION BY HASH(user_id) PARTITIONS 4;

INSERT INTO users (user_id, email, phone) VALUES (1, 'test@example.com', '13800000001');

INSERT INTO users (user_id, email, phone) VALUES (2, 'test@example.com', '13800000002');
-- ERROR 1062 (23000): Duplicate entry 'test@example.com' for key 'users.g_uk_email'.

INSERT INTO users (user_id, email, phone) VALUES (3, 'test2@example.com', '13800000001');
-- ERROR 1062 (23000): Duplicate entry '13800000001' for key 'users.g_uk_phone'.

分区 DDL 与 UPDATE GLOBAL INDEXES 子句

GSI 的索引数据跨所有分区全局存储,因此 DROP PARTITIONTRUNCATE PARTITION 这类改变分区数据的 DDL 会让原有 GSI 与底层数据不再一致。TDSQL Boundless 通过 UPDATE GLOBAL INDEXES 子句来控制此时 GSI 的处理方式。
写法
GSI 处理
结果
不带 UPDATE GLOBAL INDEXES
GSI 被标记为不可用(unusable)
DDL 执行快,但后续走 GSI 的查询会报错,需手动重建
UPDATE GLOBAL INDEXES
在 DDL 过程中同步重建 GSI
DDL 耗时增加,但 GSI 始终保持可用
下面用一张按 order_date 做 RANGE 分区、带 GSI g_idx_order_no 的订单表完整演示两种写法的差异:
-- 建表:以 order_date 按年份进行 RANGE 分区,并在 order_no 列上创建全局二级索引
CREATE TABLE orders (
order_no VARCHAR(32) NOT NULL,
order_date DATE NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
PRIMARY KEY (order_date, order_no),
INDEX g_idx_order_no (order_no) GLOBAL
) PARTITION BY RANGE (YEAR(order_date)) (
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026)
);

-- 插入测试数据(order_date 为 2023 年,数据落入 p2023 分区)
INSERT INTO orders (order_no, order_date, user_id, amount) VALUES ('NO20230601001', '2023-06-01', 1001, 99.50);

-- 写法一:未携带 UPDATE GLOBAL INDEXES。分区 DDL 执行成功并返回告警,但全局二级索引将被标记为不可用。
ALTER TABLE orders TRUNCATE PARTITION p2023;
-- Query OK, 0 rows affected, 1 warning

-- 通过 SHOW WARNINGS 查看告警详情:
SHOW WARNINGS;
-- +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-- | Level | Code | Message |
-- +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
-- | Warning | 8510 | SQLEngine system error 'Global secondary index 'g_idx_order_no' has been marked as unusable after TRUNCATE PARTITION without UPDATE GLOBAL INDEXES. Use ALTER TABLE ... UPDATE GLOBAL INDEXES to rebuild.' |
-- +---------+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

-- 索引被标记为不可用后,强制使用该全局二级索引进行查询将返回索引不存在错误:
SELECT * FROM orders FORCE INDEX(g_idx_order_no) WHERE order_no = 'NO20230601001';
-- ERROR 1176 (42000): Key 'g_idx_order_no' doesn't exist in table 'orders'.

-- 恢复方式一:执行携带 UPDATE GLOBAL INDEXES 的分区 DDL,在变更分区的同时重建全局二级索引。
ALTER TABLE orders TRUNCATE PARTITION p2024 UPDATE GLOBAL INDEXES;

-- 恢复方式二:删除后重新创建全局二级索引。
ALTER TABLE orders DROP INDEX g_idx_order_no;
ALTER TABLE orders ADD INDEX g_idx_order_no (order_no) GLOBAL;

-- 写法二:携带 UPDATE GLOBAL INDEXES。在执行分区 DDL 的同时同步重建全局二级索引,全程保持索引可用。
ALTER TABLE orders TRUNCATE PARTITION p2025 UPDATE GLOBAL INDEXES;
使用建议
尽量避免对带 GSI 的表做 DROP PARTITION / TRUNCATE PARTITION:这类分区 DDL 会让全局索引与底层数据失配,要么使 GSI 不可用,要么因同步重建 GSI 而显著拉长 DDL 耗时。若业务存在频繁的分区增删需求,应在建表设计阶段就评估是否真的需要 GSI。
若确实需要执行此类分区 DDL 且随后仍依赖 GSI 查询,应直接带上 UPDATE GLOBAL INDEXES,一步到位、避免中间出现不可用窗口。
若追求 DDL 速度、且能接受随后单独重建索引,可省略该子句,后续再执行 ALTER TABLE DROP / ADD INDEX 重建。
该子句仅作用于 DROP PARTITIONTRUNCATE PARTITION 分区操作。
该子句仅作用于全局二级索引,不影响本地索引。如果表上不存在全局二级索引,该子句不会产生额外作用。