MySQL 5.7-JSON索引-使用非标量值生成列
我一直在使用MySQL 5.7中的JSON支持。我对为索引而生成的列有几个问题 具体地说,请参考这一行: 无法为JSON列编制索引。您可以在生成的列上创建一个索引,从JSON列中提取标量值,从而绕过此限制 这对我来说似乎是一个很大的限制。无论我去哪里,人们都建议使用生成的列。但这种变通方法只适用于非常有限的一组用例。或者,我理解错了什么 搭建舞台 让我解释一下我的用例。假设您有一个名为MySQL 5.7-JSON索引-使用非标量值生成列,mysql,json,mysql-5.7,Mysql,Json,Mysql 5.7,我一直在使用MySQL 5.7中的JSON支持。我对为索引而生成的列有几个问题 具体地说,请参考这一行: 无法为JSON列编制索引。您可以在生成的列上创建一个索引,从JSON列中提取标量值,从而绕过此限制 这对我来说似乎是一个很大的限制。无论我去哪里,人们都建议使用生成的列。但这种变通方法只适用于非常有限的一组用例。或者,我理解错了什么 搭建舞台 让我解释一下我的用例。假设您有一个名为standards的表。其结构如下: CREATE TABLE `standards` ( `id` int
standards
的表。其结构如下:
CREATE TABLE `standards` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`sections` json DEFAULT NULL,
`subjects` json DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
部分
列包含一个JS对象数组:
[
{
"id": 90491,
"name": "A",
},
{
"id": 90494,
"name": "B",
}
]
subjects
列包含嵌套的JS对象:
{
"576845": {
"id": 576845,
"name": "Computer Education"
},
"576848": {
"id": 576848,
"name": "English Language"
},
"576854": {
"id": 576854,
"name": "Environmental Science"
},
"576860": {
"id": 576860,
"name": "Mathematics"
}
}
示例查询
问题1
要查找具有90494
的section ID
的Standard
记录,查询如下:
SELECT * from standards WHERE JSON_CONTAINS( sections->>'$[*].id', '90494' );
SELECT * from standards WHERE JSON_CONTAINS_PATH( subjects, 'one', '$."576854"');
问题2
要查找具有576854
的subject ID
的Standard
记录,查询如下:
SELECT * from standards WHERE JSON_CONTAINS( sections->>'$[*].id', '90494' );
SELECT * from standards WHERE JSON_CONTAINS_PATH( subjects, 'one', '$."576854"');
或
问题
现在,所有这些都起作用了。问题是查询执行完整的表扫描
考虑上面的查询1,如何生成包含所有节ID的标量数据的虚拟列
每个标准
记录都有多个节
,带有多个ID。所以,我不能仅仅创建一个整数虚拟列来存储单个值。它必须是一个节ID数组,我们需要通过它进行搜索
因此,我生成的专栏如下所示:
ALTER TABLE standards
ADD section_ids json GENERATED ALWAYS AS (sections->>'$[*].id') VIRTUAL NOT NULL;
生成的列现在只存储节ID的数组。但是我不能在生成的列上添加索引,因为它也是一个JSON列
问题-如何利用索引?
所以,问题归结到这一点——对于上面显示的查询,如何避免全表扫描
任何建议都将不胜感激。我不会说MySQL 5.7不可能做到这一点,因为它有着笨拙的解决方法和局限性,但我不会讨论如何使用该版本,因为它要困难得多,而且在许多情况下,如果可以将大量项添加到阵列中,就会达到这些局限性
但是,从现在支持的MySQL开始,这是可能的
**请注意,$.*
将获取所有对象属性,并返回格式化为数组的每个对象的查询值(.id
)
EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( sections->'$[*].id', '90494' );
EXPLAIN SELECT * from standards WHERE JSON_CONTAINS( subjects->'$.*.id', 576854 );
您将看到索引用于这些查询。在旧版本中,我将通过手动创建一个单独的索引表,并使用触发器使其保持最新状态来解决这个问题。目前在MySQL中不可行,请参阅。这太遗憾了。在您链接到的博客中,作者在3天前评论说,“JSON数组索引”仍然“在路线图上”。所以,我想这不会很快得到支持。