全局二级索引(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 分区,但要求 email、phone 在全表范围内唯一。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 PARTITION、TRUNCATE 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 PARTITION 与 TRUNCATE PARTITION 分区操作。该子句仅作用于全局二级索引,不影响本地索引。如果表上不存在全局二级索引,该子句不会产生额外作用。