如何创建一个虚拟列来索引 MySQL 中的 JSON 列?

How to create a virtual column to index JSON column in MySQL?

我正在使用 MySql 8.0 verion,我的 table 如下所示:

CREATE TABLE `table1` (
  `id` int(11) NOT NULL,
  `tableType` varchar(45) DEFAULT NULL,
  `jkey` varchar(45) DEFAULT NULL,
  `jval` json DEFAULT NULL,
  PRIMARY KEY (`id`)
) 

这里 jval 将始终有 2 个字段,如下所示:

{"group": "group1@abc.com", "user": "user1"}

{"group": "group2@abc.com", "user": "user2"}

我正在尝试将索引添加到 JSON column jval 但出现以下错误:

Operation failed: There was an error while applying the SQL script to the database.
ERROR 3152: JSON column 'jval' supports indexing only via generated columns on a specified JSON path.
SQL Statement:
ALTER TABLE `db1`.`table1` 
ADD INDEX `jval` (`value` ASC) VISIBLE

如何创建 virtual column 以在 MySQL 中索引 jval

MySQL 没有办法直接索引 JSON 文档,但它给了我们一个替代方案:生成列。 通过从 JSON 文档中的值生成列然后索引该列,我们实际上可以索引一个 JSON 字段。

Generated Columns 的语法是

column_name datatype GENERATED ALWAYS AS (expression)

你的查询会变成这样

CREATE TABLE `table1` (
  `id` int(11) NOT NULL,
  `tableType` varchar(45) DEFAULT NULL,
  `jkey` varchar(45) DEFAULT NULL,
  `jval` json NOT NULL,

  `group_virtual` VARCHAR(250) GENERATED ALWAYS AS (`jval` ->> '$.group') NOT NULL, 
  `user_virtual` VARCHAR(250) GENERATED ALWAYS AS (`jval` ->> '$.user') NOT NULL,   
  
  PRIMARY KEY (`id`)
);

您可以检查虚拟列

SHOW COLUMNS FROM `table1`;
Field Type Null Key Default Extra
id 696e74 NO PRI
tableType 7661726368617228343529 YES
jkey 7661726368617228343529 YES
jval 6a736f6e NO
group_virtual 766172636861722832353029 NO VIRTUAL GENERATED
user_virtual 766172636861722832353029 NO VIRTUAL GENERATED

如果 table 已经创建并且您想创建生成的列,则使用以下语法

ALTER TABLE
    `table1` ADD COLUMN `user_virtual` VARCHAR(250) 
     GENERATED ALWAYS AS(`jval` - >> '$.user') NOT NULL 
AFTER `jval`;

不要忘记为生成的列编制索引

CREATE INDEX `users_idx` ON `table1`(`user_virtual`); 

那就试试

SHOW INDEX FROM table1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment Visible Expression
table1 0 PRIMARY 1 id A 0 null null BTREE YES
table1 1 users_idx 1 user_virtual A 0 null null BTREE YES

db<>fiddle here