json_extract()在where中性能差,因其本质是解析后过滤而非索引查找,每次执行需全表扫描、解析json并提取路径值,无法利用b+树索引。

直接说结论:用 JSON_EXTRACT() 查嵌套 JSON 本质是“解析后过滤”,不是“索引查找”——它在 WHERE 条件里一出现,基本就放弃走索引了。
为什么 JSON_EXTRACT() 在 WHERE 中性能差
MySQL 不会对 JSON_EXTRACT(t.data, '$.items[0].price') 这类表达式自动建索引。每次执行都要全表读取 data 字段、解析整个 JSON 文档、按路径提取值,再比对。千万级表上,单次查询轻松破 5 秒。
- 即使路径写得再准(比如
'$.user.profile.name'),只要出现在WHERE或JOIN条件里,优化器就无法利用 B+ 树索引 -
JSON_CONTAINS()和JSON_OVERLAPS()同样不走索引,只是语法更简洁,底层开销没区别 - 如果 JSON 内部有数组(如
'$.tags[*].id'),JSON_EXTRACT()还得做隐式展开,CPU 和内存压力更大
什么时候可以用 JSON_EXTRACT() 安全地取值
它适合在 SELECT 列表里做“结果投影”,也就是查出来之后再解析,不参与条件过滤。
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
- 配合已通过主键 / 普通索引筛选后的少量记录使用,例如:
SELECT id, JSON_EXTRACT(data, '$.status') AS status FROM orders WHERE id IN (1001, 1002, 1003) - 用于生成报表字段或导出数据,不涉及实时响应要求
- 路径必须写死且稳定;若字段可能缺失(如
$.meta.created_at在部分记录里不存在),记得加ON EMPTY NULL避免返回NULL引发逻辑误判
替代方案:用虚拟列 + 索引才是真高效
想让嵌套字段可检索,必须把路径“固化”成普通列,再建索引。MySQL 8.0 支持生成列(virtual column)自动从 JSON 提取值。
- 添加虚拟列:
ALTER TABLE t ADD COLUMN price DECIMAL(10,2) AS (JSON_EXTRACT(data, '$.items[0].price')) STORED;(注意:要用STORED才能建索引) - 立刻建索引:
CREATE INDEX idx_price ON t(price); - 之后就能高效查询:
SELECT * FROM t WHERE price > 99.99; - ⚠️ 动态路径(如
'$.tags[*].id')无法用此法,因为虚拟列不支持数组通配符;这时只能退回到JSON_TABLE()展开后临时处理
JSON_EXTRACT() 路径写法常见翻车点
路径看似简单,但错一个符号就静默返回 NULL,很难排查。
- 数组下标从 0 开始,
'$.list[1]'是第二个元素,不是第一个 - 带空格或特殊字符的 key 必须用双引号括起来:
'$.user."full name"',写成'$.user.full name'会失败 -
->返回 JSON 类型(带引号),->>自动去引号转字符串——在WHERE里混用会导致类型隐式转换,进一步拖慢速度 - 嵌套过深(>5 层)时,解析耗时呈指数增长,建议前端或应用层提前扁平化结构
真正卡住性能的,从来不是路径怎么写,而是误以为 JSON_EXTRACT() 能像普通字段一样被索引加速。一旦数据量上来,必须切到虚拟列或 JSON_TABLE(),否则只是用数据库在做应用层该干的事。










