2026-10-21 13:17:17
MySQL 8.0引入的函数索引(Functional Index)是一项重要特性,允许基于表达式而非列值或前缀创建索引。以下是对该特性的详细解析:
一、核心功能表达式索引支持将函数/表达式结果作为索引键,例如:
CREATE TABLE t1 (col1 INT, INDEX ((ABS(col1)))); -- 对绝对值建索引CREATE INDEX idx ON t1 ((col1 + col2)); -- 对两列和建索引混合索引可混合使用函数列和普通列:
CREATE INDEX idx ON t1 (col1, (col2 * 2));排序控制支持ASC/DESC排序选项:
ALTER TABLE t1 ADD INDEX ((col1 * 40) DESC);虚拟计算列函数索引通过隐藏的虚拟列实现,会占用表的总列数限制(参考Section C.10.4)。
与计算列的关系遵循计算列的所有限制:
禁止使用子查询、变量、存储函数等
仅支持可计算列的函数(参考13.1.20.8和13.1.9.2节)
语法要求
表达式必须用双括号包裹:
INDEX ((col1 + col2)) -- 正确INDEX (col1 + col2) -- 错误禁止纯列名函数索引:
INDEX ((col1)) -- 错误,应使用普通索引INDEX (col1)前缀限制
不支持列前缀索引
替代方案:使用SUBSTRING()或CAST()
JSON数据索引需通过CAST转换数据类型并处理排序规则:
-- 方案1:索引使用与JSON_UNQUOTE相同的排序规则CREATE INDEX idx ON employees ((CAST(data->>"$.name" AS CHAR(30)) COLLATE utf8mb4_bin));-- 方案2:查询使用完整CAST表达式SELECT * FROM employees WHERE CAST(data->>'$.name' AS CHAR(30)) = 'James';外键限制外键约束不支持函数索引
索引管理
删除字段前需先删除依赖的函数索引
重复函数索引不会报错(与普通索引不同)
性能考量
复杂表达式可能增加计算开销
优化器可能无法充分利用函数索引
存储限制
函数索引使用虚拟列而非存储列
主键不能包含函数列
条件优化
-- 为WHERE ABS(col) > 100条件创建索引CREATE INDEX idx ON table1 ((ABS(col)));计算字段加速
-- 加速JSON字段查询CREATE INDEX idx ON products ((CAST(data->>'$.price' AS DECIMAL(10,2))));多列组合计算
-- 为经纬度距离计算创建索引CREATE INDEX idx ON locations ((POW(lat-30, 2) + POW(lng-120, 2)));函数索引通过表达式计算扩展了传统索引的能力,特别适合处理衍生数据、复杂条件查询等场景,但需注意其实现机制带来的限制和性能影响。