二级索引前缀压缩-SPC

更新时间:
复制 MD 格式

SPC(Secondary Prefix Compression)是PolarDB-X存储引擎中专为非唯一二级索引设计的前缀压缩功能,通过页字典去重存储相同前缀,显著节省索引存储空间。

适用范围

您的实例需满足以下版本要求:

  • 实例系列:标准版或企业版。

  • 引擎版本:MySQL 8.0。

  • 存储节点版本:xcluster8.4.20-20260423及以上版本,即2026-04-23发布的版本及之后版本。

功能简介

SPCB+Tree的叶子页面上维护一个页字典(Page Dictionary),存储页面内记录的公共前缀。每条记录只存储前缀ID和后缀数据,避免重复存储大量相同的前缀字节。

image

SPC的核心特性:

  • 页字典最多支持128个不同前缀。

  • 通过前缀去重可显著节省索引存储空间,实际节省比例取决于数据的前缀重复度。

  • 仅适用于非唯一二级索引(唯一索引可使用Panda Index)。

索引格式优先级判断顺序:PANDA > SPC > HIPPO。当多种格式同时开启时,非唯一索引优先使用SPC,唯一索引优先使用PANDA。

开启和关闭SPC

PolarDB-X实例默认关闭SPC能力。若您需要调整SPC能力的开关,可前往PolarDB分布式版控制台,在目标集群的配置与管理 > 参数设置页面的存储层页签中,调整参数opt_index_format_spc_enabled的值。此操作无需重启实例,即时生效。

同时,SPC功能支持以会话粒度控制:

-- 开启
SET SESSION opt_index_format_spc_enabled = ON;

-- 关闭(默认)
SET SESSION opt_index_format_spc_enabled = OFF;
说明

此变量控制的是新建索引时是否使用SPC格式,对已有索引无影响。

新建表时,满足条件的非唯一二级索引会自动使用SPC格式:

CREATE TABLE t1 (
  id INT NOT NULL PRIMARY KEY,
  c1 VARCHAR(200),
  c2 VARCHAR(200),
  INDEX idx_c1 (c1),        -- 自动使用SPC格式
  INDEX idx_c1c2 (c1, c2)   -- 自动使用SPC格式
) ENGINE=InnoDB;

存量索引转换为SPC

对于已有的非SPC索引,可通过以下方式转换为SPC格式(需先确保opt_index_format_spc_enabled = ON):

-- 创建新索引
ALTER TABLE ... ADD INDEX idx_new ...;
-- 更换索引名
ALTER TABLE ... RENAME idx TO idx_old, RENAME INDEX idx_new TO idx;
-- 删除原索引
ALTER TABLE ... DROP INDEX idx_old;

系统变量

变量名

作用域

类型

默认值

取值范围

说明

opt_index_format_spc_enabled

Session

Boolean

ON

ON|OFF

控制新建非唯一二级索引时是否启用SPC前缀压缩格式。仅影响新创建的索引,不影响已有索引。

innodb_spc_ddl_encode_threshold

Global

Integer

30

10~100

DDL构建SPC索引时,前缀压缩的最小数据节省比率(百分比)。值越小越倾向压缩更多页面,值越大只有压缩效果显著的页面才会被编码。

innodb_spc_ddl_encode_attempts

Global

Integer

2

1~100

DDL构建SPC索引时,每个页面通过前缀压缩进行编码的最大次数,用于防止页面被过度编码导致性能下降。

innodb_spc_analyze_sample_percentage

Global

Integer

100

0~100

执行CALL dbms_spc.analyze_table()分析SPC索引时,采样的叶子节点页面百分比。对于大表可适当降低以加快分析速度。

查看SPC索引

通过以下方式查看索引是否使用了SPC格式。

  • SHOW CREATE TABLE FOR EXPORT

    使用SHOW CREATE TABLE ... FOR EXPORT查看每个索引是否使用SPC格式。其中"spc": "true"表示该索引使用了SPC前缀压缩格式。

    SHOW CREATE TABLE t_spc_show FOR EXPORT;
    CREATE TABLE `t_spc_show` (
      `id` int NOT NULL,
      `c1` varchar(200) DEFAULT NULL,
      `c2` varchar(200) DEFAULT NULL,
      PRIMARY KEY (`id`) /*!80021 SECONDARY_ENGINE_ATTRIBUTE '{"gpp": "false", "panda index": "false", "hippo index": "false", "spc": "false"}' */,
      KEY `idx_c1` (`c1`) /*!80021 SECONDARY_ENGINE_ATTRIBUTE '{"gpp": "true", "panda index": "false", "hippo index": "false", "spc": "true"}' */,
      KEY `idx_c1c2` (`c1`,`c2`) /*!80021 SECONDARY_ENGINE_ATTRIBUTE '{"gpp": "true", "panda index": "false", "hippo index": "false", "spc": "true"}' */
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
  • INFORMATION_SCHEMA.INNODB_INDEX_STATUS

    SELECT SCHEMA_NAME, TABLE_NAME, INDEX_NAME, INDEX_PAGE_TYPE
    FROM INFORMATION_SCHEMA.INNODB_INDEX_STATUS
    WHERE TABLE_NAME = 't_spc_demo' AND SCHEMA_NAME = 'test';

    输出结果中,SPC索引的INDEX_PAGE_TYPESPC_PAGEINDEX_PAGE_TYPE取值范围说明如下:

    说明

    INDEX_PAGE

    标准B+Tree索引页

    SPC_PAGE

    SPC前缀压缩页

    PANDA_PAGE

    PANDA格式页

    RTREE_PAGE

    空间索引页

    SDI_PAGE

    数据字典索引页

统计SPC索引数量

  • 统计当前实例中所有SPC索引(按库分组):

    SELECT SCHEMA_NAME, COUNT(*) AS spc_index_count
    FROM INFORMATION_SCHEMA.INNODB_INDEX_STATUS
    WHERE INDEX_PAGE_TYPE = 'SPC_PAGE'
    GROUP BY SCHEMA_NAME;

    预期返回示例:

    +-------------+-----------------+
    | SCHEMA_NAME | spc_index_count |
    +-------------+-----------------+
    | test        |               3 |
    +-------------+-----------------+
  • 查看某个库下所有使用SPC的表和索引:

    SELECT TABLE_NAME, INDEX_NAME
    FROM INFORMATION_SCHEMA.INNODB_INDEX_STATUS
    WHERE SCHEMA_NAME = 'test' AND INDEX_PAGE_TYPE = 'SPC_PAGE';

    预期返回示例:

    +--------------+------------+
    | TABLE_NAME   | INDEX_NAME |
    +--------------+------------+
    | t_spc_demo   | idx_c1     |
    | t_spc_demo   | idx_c1c2   |
    | t_mixed_demo | idx_c2     |
    +--------------+------------+

压缩统计分析

  • 通过dbms_spc.analyze_table存储过程,查看SPC索引的详细压缩统计信息:

    CALL dbms_spc.analyze_table('table_name');
    -- 或指定数据库
    CALL dbms_spc.analyze_table('db_name.table_name');

    输出指标说明:

    指标

    含义

    rec_bytes

    页面上所有记录的总字节数

    row_bytes

    实际行数据的总字节数

    comp_recs

    已压缩的记录数

    uncomp_recs

    未压缩的记录数

    dict_bytes

    页字典区域占用的字节数

    dict_slots

    页字典中的槽位总数

    dict_unused_slots

    页字典中未被任何记录引用的冗余前缀数量

    spc_page

    SPC格式的页面数

    compression ratio

    压缩比,表示通过SPC可节省的空间比例

  • 采样率控制:您可以通过innodb_spc_analyze_sample_percentage变量控制分析时的采样比例(默认 100,即采样所有页面):

    -- 采样 50% 的页面
    SET GLOBAL innodb_spc_analyze_sample_percentage = 50;  

使用限制

  • 实例版本:由于SPC涉及底层存储结构变动,使用了SPC的实例无法降级至不支持SPC的老版本。

  • 存量索引处理:对于已存在的二级索引,在开启SPC后不会自动转换为SPC索引。您可以通过删除并重建索引的方式进行转换。

    1. 创建新索引:ALTER TABLE ... ADD INDEX idx_new ...;

    2. 更换索引名:ALTER TABLE ... RENAME idx TO idx_old, RENAME INDEX idx_new TO idx;

    3. 删除原索引:ALTER TABLE ... DROP INDEX idx_old;

  • 不支持SPC的表类型

    • 压缩表(ROW_FORMAT=COMPRESSED

    • 临时表(TEMPORARY TABLE

    • 系统表

    • COMPACTDYNAMIC行格式的表

    • 16KB页大小(仅支持innodb_page_size = 16384

  • 不支持SPC的索引类型

    • 唯一索引(UNIQUE KEY):使用PANDA格式

    • 聚集索引(PRIMARY KEY):使用标准格式

    • 全文索引(FULLTEXT INDEX)

    • 空间索引(SPATIAL INDEX)

    • 多值索引(Multi-Value Index)

    • 包含虚拟列的索引

  • DDL行为变化:通常情况下,VARCHAR列的长度扩展只需更新数据字典即可完成,不需要重建表。但如果涉及SPC索引(存量SPC索引的列或新建SPC索引的VARCHAR列发生长度变化),DDL会被强制升级为INPLACE表重建,并产生如下警告:

    Warning 1088: Extending column 'X' requires table rebuild because it is part of an SPC index

    原因是列长度变化会导致SPC索引的页字典容量需要重新计算,而这只能通过重建表来完成。

  • 导出/导入限制

    限制条件

    说明

    格式必须匹配

    源表和目标表的索引格式(SPC与非SPC)必须完全一致。

    CFG版本要求

    需要CFG V9格式支持,旧版本导出的.cfg文件无法包含SPC信息。

    不支持跨版本

    旧版本(不支持SPC)导出的表空间无法直接导入为SPC格式。

    页字典容量必须一致

    源和目标的表结构必须一致,以保证页字典容量计算结果相同。