用CREATE INDEX直接在JSON路径表达式上建功能索引,验证它跟上一篇具名生成列索引相比,不会在表结构里留下任何多余的列。
上一篇用了具名STORED生成列,这次试试MySQL 8+支持的"功能索引"。
代码CREATE TABLE t7 (id INT PRIMARY KEY AUTO_INCREMENT, payload JSON); INSERT INTO t7 (payload) VALUES ('{"city":"Beijing"}'),('{"city":"Shanghai"}'); CREATE INDEX idx_func ON t7 ((CAST(payload->>'$.city' AS CHAR(50))));
跟上一篇的具名生成列写法对照。
结果SHOW CREATE TABLE t7 → ... KEY `idx_func` ((cast(json_unquote(json_extract(`payload`,'$.city')) as char(50) charset utf8mb4))) ...
建表语句里看不到任何叫 city 或类似名字的具名列——索引直接定义在表达式本身上,语法上跟"先建生成列再对它建索引"完全不同。
这是跟上一篇最大的区别。
结果SHOW COLUMNS FROM t7 → id int ... → payload json ... (只有这两列,没有第三列!)
MySQL在内部为这个功能索引创建了一个隐藏的虚拟生成列(这是实现功能索引的底层机制),但这个隐藏列不会出现在正常的列列表里——业务代码、ORM框架、DESC语句看到的表结构还是干干净净的两列,不会像上一篇具名生成列那样在SELECT *、DESC等地方多冒出一列。
语法不同,底层能力一致。
结果EXPLAIN SELECT id FROM t7 WHERE CAST(payload->>'$.city' AS CHAR(50)) = 'Beijing' → Index lookup on t7 using idx_func (...) (cost=0.35 rows=1) 新插入一行'{"city":"Guangzhou"}'后立刻能查到,索引自动维护,跟生成列无异
GENERATED ALWAYS AS (...) STORED;只是单纯想给一个表达式建索引、不想让表结构多出额外的列,用 CREATE INDEX ... ((表达式)) 这种功能索引写法——没有哪个更好,取决于你要不要这个中间值本身作为一个字段暴露出来。
每一步都是本文上面用EXPLAIN和SHOW COLUMNS跑出来的原始结果。
CREATE INDEX ... ((表达式)):验证隐藏生成列不出现在SHOW COLUMNS里