json_table将json字段在数据库内核展开为行,避免应用层解析oom;必须正确使用path路径、nested path处理嵌套、on empty/on error容错及for ordinality序号。

直接用 JSON_TABLE 把 JSON 字段“展开”成行,而不是在应用层 json.loads() + 循环解析 —— 这是性能分水岭。万级订单、每个含几十项商品时,应用层解析极易 OOM;而 JSON_TABLE 在数据库内核完成路径匹配与行生成,避免全量数据往返和重复解析。
路径表达式写错:不是语法糖,是硬性约束
JSON_TABLE 的第二个参数(path)不可省略,且必须指向一个可展开的结构单元。常见错误包括:
- 写成
'$.[*]'(多了一个点),正确应为'$[*]' - 源 JSON 是对象
{"items": [...]},却用'$[*]'试图遍历根 —— 根不是数组,会报ERROR 3149 (HY000): The JSON path is not valid for the given JSON document - 路径中漏引号,如
$.items[*]写成$.items[*](未加单引号),MySQL 直接报ERROR 3143 (42000): Invalid path expression - 对嵌套数组误用顶层 PATH,比如想取
$.items[*].price却没声明NESTED PATH,结果 price 全为NULL
嵌套数组必须用 NESTED PATH,不能靠 COLUMNS 硬套
当 JSON 是 “对象包数组” 结构(如 {"order_id": 1, "items": [{"id": 101}, {"id": 102}]}),想同时拉出 order_id 和每个 item.id,下面写法是错的:
JSON_TABLE(o.order_data, '$' COLUMNS ( order_id INT PATH '$.order_id', item_id INT PATH '$.items[*].id' -- ❌ 路径越界,不生效 ))
正确做法是分层定义:
JSON_TABLE(o.order_data, '$' COLUMNS (
order_id INT PATH '$.order_id',
NESTED PATH '$.items[*]' COLUMNS (
item_id INT PATH '$.id'
)
)) AS jt
注意:NESTED PATH 必须嵌在最外层 COLUMNS 内;子 COLUMNS 中的 PATH 以当前数组元素为根(即 $ 指向每个 {"id": 101} 对象);1 条原始记录 + 3 个 items → 输出 3 行。
空值与类型容错:ON ERROR 和 DEFAULT ON EMPTY 不是可选项
生产环境 JSON 字段缺失极常见。不加容错,字段一空整行就丢。必须显式控制:
-
name VARCHAR(50) PATH '$.name' DEFAULT 'unknown' ON ERROR DEFAULT 'error':字段不存在或类型错时填'unknown';解析失败(如'$.name'实际是数字)时填'error' -
score INT PATH '$.score' DEFAULT 0 ON EMPTY DEFAULT 0 ON ERROR DEFAULT -1:覆盖空值、缺失、类型异常三种场景 - 漏掉
DEFAULT ON EMPTY,遇到"name": null或字段完全缺失,该列就是NULL,可能引发后续WHERE或JOIN异常
FOR ORDINALITY 也建议加上,尤其做去重或排序时:row_num FOR ORDINALITY 可获得数组内原始顺序索引,避免因 MySQL 内部展开顺序不确定导致逻辑错乱。
真正难的不是写出第一个能跑的 JSON_TABLE 查询,而是把路径写对、把嵌套层级理清、把每种空值场景都兜住 —— 这三处任一疏漏,上线后查不出数据、聚合结果少行、字段全 NULL,问题都极难定位。










