通过“提取标量值”,这是否意味着我必须分别提取和索引数组中的每个项目 [...]?
您可以提取任意数量的项目。它们将存储为标量(例如字符串),而不是复合值(JSON 就是这样)。
CREATE TABLE mytags (
id INT NOT NULL AUTO_INCREMENT,
tags JSON,
PRIMARY KEY (id)
);
INSERT INTO mytags (tags) VALUES
('["tag1", "tag2", "tag3"]'),
('["tag1", "tag3", "tag5", "tag7"]'),
('["tag2", "tag5"]');
SELECT * FROM mytags;
+----+----------------------------------+
| id | tags |
+----+----------------------------------+
| 1 | ["tag1", "tag2", "tag3"] |
| 2 | ["tag1", "tag3", "tag5", "tag7"] |
| 3 | ["tag2", "tag5"] |
+----+----------------------------------+
让我们创建一个仅包含一项的索引(来自 JSON 对象的第一个值):
ALTER TABLE mytags
ADD COLUMN tags_scalar VARCHAR(255) GENERATED ALWAYS AS (json_extract(tags, '$[0]')),
ADD INDEX tags_index (tags_scalar);
SELECT * FROM mytags;
+----+----------------------------------+-------------+
| id | tags | tags_scalar |
+----+----------------------------------+-------------+
| 1 | ["tag1", "tag2", "tag3"] | "tag1" |
| 2 | ["tag1", "tag3", "tag5", "tag7"] | "tag1" |
| 3 | ["tag2", "tag5"] | "tag2" |
+----+----------------------------------+-------------+
现在您在 VARCHAR 列 tags_scalar 上有一个索引。该值包含引号,也可以跳过:
ALTER TABLE mytags DROP COLUMN tags_scalar, DROP INDEX tags_index;
ALTER TABLE mytags
ADD COLUMN tags_scalar VARCHAR(255) GENERATED ALWAYS AS (json_unquote(json_extract(tags, '$[0]'))),
ADD INDEX tags_index (tags_scalar);
SELECT * FROM mytags;
+----+----------------------------------+-------------+
| id | tags | tags_scalar |
+----+----------------------------------+-------------+
| 1 | ["tag1", "tag2", "tag3"] | tag1 |
| 2 | ["tag1", "tag3", "tag5", "tag7"] | tag1 |
| 3 | ["tag2", "tag5"] | tag2 |
+----+----------------------------------+-------------+
正如您已经想象的那样,生成的列可以包含更多来自 JSON 的项目:
ALTER TABLE mytags DROP COLUMN tags_scalar, DROP INDEX tags_index;
ALTER TABLE mytags
ADD COLUMN tags_scalar VARCHAR(255) GENERATED ALWAYS AS (json_extract(tags, '$[0]', '$[1]', '$[2]')),
ADD INDEX tags_index (tags_scalar);
SELECT * from mytags;
+----+----------------------------------+--------------------------+
| id | tags | tags_scalar |
+----+----------------------------------+--------------------------+
| 1 | ["tag1", "tag2", "tag3"] | ["tag1", "tag2", "tag3"] |
| 2 | ["tag1", "tag3", "tag5", "tag7"] | ["tag1", "tag3", "tag5"] |
| 3 | ["tag2", "tag5"] | ["tag2", "tag5"] |
+----+----------------------------------+--------------------------+
或使用any other valid expression从JSON结构中自动生成一个字符串,以获得可以轻松索引和搜索的内容,例如“tag1tag3tag5tag7”。
[...](意思是我必须知道数组的最大长度才能全部索引)?
如上所述,您无需知道 - 可以使用任何有效的表达式跳过 NULL 值。但当然知道总是更好。
现在是架构决策:JSON 数据类型最适合实现目标吗?解决这个特殊问题? JSON在这里是正确的工具吗?它会加快搜索速度吗?
如何索引可变长度数组?
如果你坚持,请转换字符串:
ALTER TABLE mytags DROP COLUMN tags_scalar, DROP INDEX tags_index;
ALTER TABLE mytags
ADD COLUMN tags_scalar VARCHAR(255) GENERATED ALWAYS AS (replace(replace(replace(cast(tags as char), '"', ''), '[', ''), ']', '')),
ADD INDEX tags_index (tags_scalar);
SELECT * from mytags;
+----+----------------------------------+------------------------+
| id | tags | tags_scalar |
+----+----------------------------------+------------------------+
| 1 | ["tag1", "tag2", "tag3"] | tag1, tag2, tag3 |
| 2 | ["tag1", "tag3", "tag5", "tag7"] | tag1, tag3, tag5, tag7 |
| 3 | ["tag2", "tag5"] | tag2, tag5 |
+----+----------------------------------+------------------------+
这样或那样你最终会得到一个 VARCHAR 或 TEXT 列,在其中应用最适用的索引结构 (some options)。
进一步阅读: