mysql 8.0.30 不支持标准部分索引(即带 where 条件的索引),所谓“部分索引”效果均由函数索引、前缀索引或分区表+局部索引模拟实现,无法真正实现仅对满足条件的行建立索引。

直接说结论:对海量历史数据,PARTIAL INDEX(部分索引)在 MySQL 中并不存在——MySQL 直到 8.0.30 仍不支持标准意义上的部分索引(即 WHERE 条件过滤的索引),你看到的“部分索引”效果,基本都是靠函数索引、前缀索引或分区表+局部索引模拟出来的。
MySQL 有 partial index 吗?
没有。PostgreSQL 有 CREATE INDEX ... WHERE,SQL Server 有 FILTERED INDEX,但 MySQL 的 CREATE INDEX 语法不接受 WHERE 子句。所谓“为历史数据建部分索引”,本质是绕过这个限制的工程妥协:
- 你不能写
CREATE INDEX idx_guid_recent ON t(guid) WHERE create_time > '2025-01-01'—— 这会报语法错误 - MySQL 8.0+ 支持函数索引(如
CAST(create_time AS DATE)),但它索引的是所有行,不是“只索引满足条件的行” - 真正能实现“仅索引最近数据”的方案,只有表分区 + 分区级索引,或业务层控制写入路由
用前缀索引假装“部分索引”?小心失效
前缀索引(INDEX(col(10)))常被误认为可减少索引体积、提升历史数据查询效率,但它解决的是“单字段值太长”的问题,不是“数据时间跨度大”的问题:
-
CREATE INDEX idx_content_prefix ON t(content(20))只取前 20 字节建 B+ 树,对中文模糊匹配几乎无效(一个汉字占 3 字节,20 字节 ≈ 6 个字) - 前缀长度选小了,
SELECT ... WHERE content LIKE '订单%'可能无法利用索引;选大了,索引体积暴涨,缓冲池压力反而上升 - 它对
create_time这类时间字段完全无意义——create_time(5)是非法语法,MySQL 不允许对日期类型指定前缀长度
真正可行的“历史数据轻量索引”方案
面对三个月 3.6 亿条数据,想让“最近 7 天数据快、老数据慢但可查”,得放弃“单表 + 单索引”幻想,转向结构化隔离:
-
按天分表 + 索引下沉:建
t_20260601、t_20260602… 每张表只存当天 400 万条,并在每张表上独立建guid、create_time索引。老表可删索引或设为READ ONLY,新表索引保持活跃 -
Range 分区 + 分区裁剪:用
PARTITION BY RANGE (TO_DAYS(create_time)),把三个月拆成 90 个分区。查询WHERE create_time BETWEEN '2026-06-01' AND '2026-06-07'时,MySQL 只扫描 7 个分区,索引也只在这 7 个分区上生效 -
冷热分离 + 联合查询:把最近 7 天数据放
t_hot(带完整索引),历史数据归档到t_archive(仅主键索引)。应用层判断时间范围,自动路由到对应表;必要时用UNION ALL合并结果
函数索引能替代部分索引吗?
MySQL 8.0.13+ 支持函数索引,但它不是“条件过滤索引”,而是“表达式计算索引”。例如:
CREATE INDEX idx_guid_lower ON t((LOWER(guid)));
这索引的是所有行的 LOWER(guid) 值,不是“只索引 guid 非空的行”。如果你真想“只索引最近数据”,唯一办法是先用分区或分表把数据物理隔离,再在子集上建普通索引——函数索引在这里只是锦上添花,不是破局点。
最容易被忽略的一点:分区表的 create_time 字段必须是 INT 或 DATE 类型且参与分区表达式,否则分区裁剪失效;而函数索引若引用了未定义的列或非常量表达式(如 NOW()),建索引会直接失败。











