mongo切换ob,过滤json类型中的字段咨询

【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】OB
【 使用版本 】4.4.2-ce
【问题描述】
想过滤json字段中的某个字段,应该如何建表,这个是json字段的数据示例,想要过滤addr,匹配到了就直接返回整行数据。

[{"mac": "", "addr": "172.018.005.180", "type": 0}, {"mac": "", "addr": "172.018.005.181", "type": 0}]

下面是遇到的问题。

  1. 多值索引,建表后不能添加多值索引,必须要建表时指定,但是未来可能会扩展过滤更多字段。
    建表语句:
  CREATE TABLE `host_nic_config` (
    `id`           BIGINT       NOT NULL AUTO_INCREMENT,
    `host_id`      BIGINT       NOT NULL COMMENT '关联主机 ID',
    `config_name`  VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '配置名',
    `addresses`    JSON         NOT NULL COMMENT '网卡地址数组 [{"mac":"","addr":"172.018.005.180","type":0}]',
    `created_at`   DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at`   DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_host` (`host_id`)
  ) ENGINE = InnoDB
    DEFAULT CHARSET = utf8mb4
    COMMENT = '主机网卡配置(JSON 数组)';

建索引失败。

mysql> CREATE INDEX addr_test ON host_nic_config ((CAST(addresses->'$[*].addr' AS CHAR(255) ARRAY)));
ERROR 1235 (0A000): build multivalue index afterward not supported

数据示例:

  INSERT INTO host_nic_config (host_id, config_name, addresses) VALUES
  (1001, 'default',
   '[{"mac":"","addr":"172.018.005.180","type":0},{"mac":"","addr":"172.018.005.181","type":0}]'),
  (1002, 'default',
   '[{"mac":"aa:bb:cc:dd:ee:01","addr":"172.018.005.182","type":1}]'),
  (1003, 'bond0',
   '[{"mac":"aa:bb:cc:dd:ee:02","addr":"172.018.005.183","type":0},{"mac":"aa:bb:cc:dd:ee:03","addr":"172.018.005.184","type":0}]'),
  (1004, 'default',
   '[{"mac":"","addr":"172.018.005.180","type":0}]');
  1. 生成列,可以查询。
mysql> ALTER TABLE host_nic_config ADD COLUMN all_addrs VARCHAR(1024) GENERATED ALWAYS AS (JSON_EXTRACT(addresses, '$[*].addr')) STORED;
Query OK, 0 rows affected (2.12 sec)

mysql> SELECT * FROM host_nic_config
    -> WHERE JSON_CONTAINS(all_addrs, '"172.018.005.180"');
+----+---------+-------------+--------------------------------------------------------------------------------------------------------+---------------------+---------------------+----------------------------------------+
| id | host_id | config_name | addresses                                                                                              | created_at          | updated_at          | all_addrs                              |
+----+---------+-------------+--------------------------------------------------------------------------------------------------------+---------------------+---------------------+----------------------------------------+
|  1 |    1001 | default     | [{"mac": "", "addr": "172.018.005.180", "type": 0}, {"mac": "", "addr": "172.018.005.181", "type": 0}] | 2026-07-27 16:33:20 | 2026-07-27 16:33:20 | ["172.018.005.180", "172.018.005.181"] |
|  4 |    1004 | default     | [{"mac": "", "addr": "172.018.005.180", "type": 0}]                                                    | 2026-07-27 16:33:20 | 2026-07-27 16:33:20 | ["172.018.005.180"]                    |
|  5 |    1006 | default     | [{"mac": "", "addr": "172.018.005.180", "type": 0}, {"mac": "", "addr": "172.018.005.181", "type": 0}] | 2026-07-27 19:29:15 | 2026-07-27 19:29:15 | ["172.018.005.180", "172.018.005.181"] |
+----+---------+-------------+--------------------------------------------------------------------------------------------------------+---------------------+---------------------+----------------------------------------+
3 rows in set (0.01 sec)

建索引,无法查询。

mysql> ALTER TABLE host_nic_config ADD INDEX idx_all_addrs (all_addrs);
Query OK, 0 rows affected (0.88 sec)

mysql> SELECT * FROM host_nic_config  WHERE JSON_CONTAINS(all_addrs, '"172.018.005.180"');
Empty set (0.03 sec)

mysql> SELECT * FROM host_nic_config  WHERE all_addrs = "172.018.005.180";
Empty set (0.00 sec)

可能要建全文索引?但是保证不了性能?

7 个赞

学习

1、OceanBase 默认不支持在建表后再加多值索引。
2、 普通 B-Tree 索引按整列值建索引,不是按数组里的单个元素。加索引后,优化器可能错误地走索引查找(按完整字符串匹配),导致 JSON_CONTAINS 返回空结果。这是索引类型与查询语义不匹配,不是 JSON_CONTAINS 本身的问题。

sys租户打开这个隐藏参数 就可以后建多值索引

https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000005283560

请问针对这个场景,有什么建议或者参考么?

有没有考虑过,OB不是用来替换Mongo的。

1、数据量不大、查询不频繁:生成列 + 全表扫描就可以。 注意:JSON 数组字符串不要建普通 B-Tree 索引
2、如果数据量大、要高性能、字段相对固定:建表时定义好多值索引
3、如果未来会频繁扩展过滤字段:关联表最灵活

请问后建多值索引开启的话有什么影响?这个相较于建表时的多值索引性能有差别么?
@淇铭 @旭辉

之前版本有bug

请问4.4.2-ce和4.6.0-ce都修复了么?性能跟建表时创建没差别吧?后建多值索引创建时会锁表么?

修复了,性能没差别,后建多值索引是online ddl

逻辑清晰。