Json 类型与多值索引 — OceanBase 4.3.2 AP 功能体验

本文来自 2024年OceanBase技术征文大赛——“让技术被看见 | OceanBase 布道师计划”的用户征文。也欢迎更多的技术爱好者参与征文,赢取万元大奖。和我们一起,用文字让代码跳动起来!   参与2024年OceanBase技术征文大赛>>

MySQL在5.7.8版本中引入了JSON数据类型及相应的JSON函数,而在8.0.17版本中,又推出了针对值数组的多值索引。这些功能非常实用,一度成为  ​​​MySQL迁移到OceanBase 上的一个阻点。之前,OceanBase 在 3.2.2版本推出了JSON数据类型及JSON函数,4.3.2版本则实现了多值索引。本文将分享OceanBase 4.3.2版本中JSON数据类型及其索引的使用示例和实践。


OB 的 ORACLE 租户和 MySQL 租户都支持 JSON 类型,本文主要演示 MySQL 租户下的 JSON 使用。

首先创建一个含有 JSON 类型的表,示例参考 MySQL 官方文档中 JSON 示例表。

CREATE TABLE customers (
     id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
     modified DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     custinfo JSON
 );
 
 INSERT INTO customers VALUES
 (NULL, NOW(), '{"user":"Jack","user_id":37,"zipcode":[94582,94536]}'),
 (NULL, NOW(), '{"user":"Jill","user_id":22,"zipcode":[94568,94507,94582]}'),
 (NULL, NOW(), '{"user":"Bob","user_id":31,"zipcode":[94477,94507]}'),
 (NULL, NOW(), '{"user":"Mary","user_id":72,"zipcode":[94536]}'),
 (NULL, NOW(), '{"user":"Ted","user_id":56,"zipcode":[94507,94582]}')
;

select * from customers;

1730180347

JSON 列不支持直接索引,如果想对 JSON 列部分字段做索引,可以新增一个虚拟列,然后针对这个虚拟列创建索引。

ALTER TABLE customers ADD v_user varchar(20) GENERATED ALWAYS AS (json_unquote(json_extract (`custinfo`, _utf8mb4'$.user'))) virtual ;
ALTER TABLE customers ADD KEY idx_user(v_user);

1730180359

再看看查询虚拟列的执行计划。

mysql> explain SELECT * FROM customers WHERE v_user='Bob';
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                                         |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ===============================================================                                                                                                                    |
| |ID|OPERATOR        |NAME               |EST.ROWS|EST.TIME(us)|                                                                                                                    |
| ---------------------------------------------------------------                                                                                                                    |
| |0 |TABLE RANGE SCAN|customers(idx_user)|1       |7           |                                                                                                                    |
| ===============================================================                                                                                                                    |
| Outputs & filters:                                                                                                                                                                 |
| -------------------------------------                                                                                                                                              |
|   0 - output([customers.id], [customers.modified], [customers.custinfo], [column_conv(VARCHAR,utf8mb4_general_ci,length:20,NULL,cast(json_unquote(json_extract(customers.custinfo, |
|        '$.user')), VARCHAR(1048576)))]), filter(nil)                                                                                                                               |
|       access([customers.id], [customers.custinfo], [customers.v_user], [customers.modified]), partitions(p0)                                                                       |
|       is_index_back=true, is_global_index=false,                                                                                                                                   |
|       range_key([customers.v_user], [customers.id]), range(Bob,MIN ; Bob,MAX),                                                                                                     |
|       range_cond([customers.v_user = 'Bob'])                                                                                                                                       |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
13 rows in set, 1 warning (0.02 sec)

上面方法如果要对 JSON 字段 zipcode 做索引就有点困难,这个列的值是个数组。这就用到新推出的多值索引功能。

先看查询场景 SQL 。

EXPLAIN SELECT * FROM customers WHERE 94507 MEMBER OF(custinfo->'$.zipcode');
EXPLAIN SELECT * FROM customers WHERE JSON_CONTAINS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
EXPLAIN SELECT * FROM customers WHERE JSON_OVERLAPS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));

这三个 SQL 使用了常见的 JSON 函数,执行计划全部是全表扫描就不发了。应对方法就是新增多值索引。

mysql> ALTER TABLE customers ADD INDEX zips( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) );
ERROR 1235 (0A000): dynamic add multivalue index not supported yet not supported
mysql> 

遗憾的是由于 OB 4.3.2 是刚支持多值索引,目前还只实现在建表的时候创建多值索引,暂不支持后期动态添加多值索引。

所以我们再创建一个带多值索引的新表看看。

create table customers2(
  id bigint not null auto_increment  ,
  modified datetime default current_timestamp on update current_timestamp,
  custinfo json,
  index zips((cast(custinfo->'$.zipcode' as unsigned array))),
  INDEX comp(id, modified,(cast(custinfo->'$.zipcode' as unsigned array)))
);

INSERT INTO customers2 SELECT * FROM customers;

为了减少篇幅,我这里一次性创建两类多值索引。一个是针对单列的多值索引,一个是多列组合索引。

mysql> EXPLAIN SELECT * FROM customers2 WHERE 94507 MEMBER OF(custinfo->'$.zipcode');                                                                                                                                                                                       
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+                                                                                                            
| Query Plan                                                                                                                                                   |                                                                                                            
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+                                                                                                            
| ===========================================================                                                                                                  |                                                                                                            
| |ID|OPERATOR       |NAME            |EST.ROWS|EST.TIME(us)|                                                                                                  |                                                                                                            
| -----------------------------------------------------------                                                                                                  |                                                                                                            
| |0 |TABLE FULL SCAN|customers2(zips)|2       |13          |                                                                                                  |                                                                                                            
| ===========================================================                                                                                                  |                                                                                                            
| Outputs & filters:                                                                                                                                           |                                                                                                            
| -------------------------------------                                                                                                                        |                                                                                                            
|   0 - output([customers2.id], [customers2.modified], [customers2.custinfo]), filter([JSON_MEMBER_OF(94507, JSON_EXTRACT(customers2.custinfo, '$.zipcode'))]) |                                                                                                            
|       access([customers2.__pk_increment], [customers2.custinfo], [customers2.id], [customers2.modified]), partitions(p0)                                     |                                                                                                            
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],                                                                             |                                                                                                            
|       range_key([customers2.SYS_NC_mvi_19], [customers2.__pk_increment], [customers2.__doc_id_1727685398954214]), range(94507,MIN,MIN ; 94507,MAX,MAX)       |                                                                                                            
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+                                                                                                            
11 rows in set (0.00 sec)                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                            
mysql> EXPLAIN SELECT * FROM customers2 WHERE JSON_CONTAINS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));                                                                                                                                                          
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+                                                                                                        
| Query Plan                                                                                                                                                       |                                                                                                        
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+                                                                                                        
| ===========================================================                                                                                                      |                                                                                                        
| |ID|OPERATOR       |NAME            |EST.ROWS|EST.TIME(us)|                                                                                                      |                                                                                                        
| -----------------------------------------------------------                                                                                                      |                                                                                                        
| |0 |TABLE FULL SCAN|customers2(zips)|3       |23          |                                                                                                      |                                                                                                        
| ===========================================================                                                                                                      |                                                                                                        
| Outputs & filters:                                                                                                                                               |                                                                                                        
| -------------------------------------                                                                                                                            |
|   0 - output([customers2.id], [customers2.modified], [customers2.custinfo]), filter([JSON_CONTAINS(JSON_EXTRACT(customers2.custinfo, '$.zipcode'), cast('[94507, |
|       94582]', JSON(536870911)))])                                                                                                                               |
|       access([customers2.__pk_increment], [customers2.custinfo], [customers2.id], [customers2.modified]), partitions(p0)                                         |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],                                                                                 |
|       range_key([customers2.SYS_NC_mvi_19], [customers2.__pk_increment], [customers2.__doc_id_1727685398954214]), range(94507,MIN,MIN ; 94507,MAX,MAX),          |
|       (94582,MIN,MIN ; 94582,MAX,MAX)                                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
13 rows in set (0.00 sec)
mysql> EXPLAIN SELECT * FROM customers2 WHERE JSON_OVERLAPS(custinfo->'$.zipcode', CAST('[94507,94582]' AS JSON));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                       |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ===========================================================                                                                                                      |
| |ID|OPERATOR       |NAME            |EST.ROWS|EST.TIME(us)|                                                                                                      |
| -----------------------------------------------------------                                                                                                      |
| |0 |TABLE FULL SCAN|customers2(zips)|3       |23          |                                                                                                      |
| ===========================================================                                                                                                      |
| Outputs & filters:                                                                                                                                               |
| -------------------------------------                                                                                                                            |
|   0 - output([customers2.id], [customers2.modified], [customers2.custinfo]), filter([JSON_OVERLAPS(JSON_EXTRACT(customers2.custinfo, '$.zipcode'), cast('[94507, |
|       94582]', JSON(536870911)))])                                                                                                                               |
|       access([customers2.__pk_increment], [customers2.custinfo], [customers2.id], [customers2.modified]), partitions(p0)                                         |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],                                                                                 |
|       range_key([customers2.SYS_NC_mvi_19], [customers2.__pk_increment], [customers2.__doc_id_1727685398954214]), range(94507,MIN,MIN ; 94507,MAX,MAX),          |
|       (94582,MIN,MIN ; 94582,MAX,MAX)                                                                                                                            |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------+
13 rows in set (0.00 sec)

mysql> EXPLAIN SELECT * FROM customers2 WHERE id = 23 and modified = 103 and 94507 MEMBER OF(custinfo->'$.zipcode');
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                   |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ============================================================                                                                                                 |
| |ID|OPERATOR        |NAME            |EST.ROWS|EST.TIME(us)|                                                                                                 |
| ------------------------------------------------------------                                                                                                 |
| |0 |TABLE RANGE SCAN|customers2(comp)|1       |7           |                                                                                                 |
| ============================================================                                                                                                 |
| Outputs & filters:                                                                                                                                           |
| -------------------------------------                                                                                                                        |
|   0 - output([customers2.id], [customers2.modified], [customers2.custinfo]), filter([JSON_MEMBER_OF(94507, JSON_EXTRACT(customers2.custinfo, '$.zipcode'))]) |
|       access([customers2.__pk_increment], [customers2.custinfo], [customers2.id], [customers2.modified]), partitions(p0)                                     |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],                                                                             |
|       range_key([customers2.id], [customers2.modified], [customers2.SYS_NC_mvi_21], [customers2.__pk_increment], [customers2.__doc_id_1727685398954214]),    |
|        range(23,2000-01-03 00:00:00.000000,MIN,MIN,MIN ; 23,2000-01-03 00:00:00.000000,MAX,MAX,MAX),                                                         |
|       range_cond([customers2.id = 23], [customers2.modified = INTERNAL_FUNCTION(103, 110, 17)])                                                              |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
13 rows in set (0.00 sec)

这里直接将 4 种使用多值索引的查询场景 SQL 以及执行计划放出,这执行计划中的细节大家可以一一详细查看。

多值索引的结构如下。

mysql> show indexes from customers2;
+------------+------------+----------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name               | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment   | Index_comment | Visible | Expression                                                                                                                     |
+------------+------------+----------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
| customers2 |          1 | zips     |            1 | SYS_NC_mvi_19             | A         |        NULL | NULL     | NULL   | YES  | BTREE      | available |               | YES     | json_query(`custinfo`,'$.zipcode' RETURNING unsigned WITHOUT ARRAY WRAPPER asis error on error null on empty null on mismatch) |
| customers2 |          1 | zips     |            2 | __pk_increment            | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers2 |          1 | zips     |            3 | __doc_id_1727685398954214 | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers2 |          1 | comp     |            1 | id                        | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers2 |          1 | comp     |            2 | modified                  | A         |        NULL | NULL     | NULL   | YES  | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers2 |          1 | comp     |            3 | SYS_NC_mvi_21             | A         |        NULL | NULL     | NULL   | YES  | BTREE      | available |               | YES     | json_query(`custinfo`,'$.zipcode' RETURNING unsigned WITHOUT ARRAY WRAPPER asis error on error null on empty null on mismatch) |
| customers2 |          1 | comp     |            4 | __pk_increment            | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers2 |          1 | comp     |            5 | __doc_id_1727685398954214 | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
+------------+------------+----------+--------------+---------------------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
8 rows in set (0.00 sec)

还有一类特殊的场景是多值索引的唯一性索引。

CREATE TABLE customers3 (
 id BIGINT not null primary key,
 modified BIGINT not null,
 custinfo JSON,
 UNIQUE INDEX zips1( (CAST(custinfo->'$.zipcode' AS UNSIGNED ARRAY)) )
);

INSERT INTO customers3 VALUES
 (10, 21, '{"user":"Jack","user_id":37,"zipcode":[94582,94536]}');
 
mysql> select * from customers3;
+----+----------+------------------------------------------------------------+
| id | modified | custinfo                                                   |
+----+----------+------------------------------------------------------------+
| 10 |       21 | {"user": "Jack", "user_id": 37, "zipcode": [94582, 94536]} |
+----+----------+------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> INSERT INTO customers3 VALUES  (11, 22, '{"user":"Jill","user_id":22,"zipcode":[94568,94507,94582]}');
ERROR 1062 (23000): Duplicate entry '94582' for key 'zips1'
mysql> 

mysql> show indexes from customers3;
+------------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
| Table      | Non_unique | Key_name | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment   | Index_comment | Visible | Expression                                                                                                                     |
+------------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
| customers3 |          0 | PRIMARY  |            1 | id            | A         |        NULL | NULL     | NULL   |      | BTREE      | available |               | YES     | NULL                                                                                                                           |
| customers3 |          0 | zips1    |            1 | SYS_NC_mvi_19 | A         |        NULL | NULL     | NULL   | YES  | BTREE      | available |               | YES     | json_query(`custinfo`,'$.zipcode' RETURNING unsigned WITHOUT ARRAY WRAPPER asis error on error null on empty null on mismatch) |
+------------+------------+----------+--------------+---------------+-----------+-------------+----------+--------+------+------------+-----------+---------------+---------+--------------------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

由此可见唯一性的多值索引能拦截导致多值数组中出现重复的值。

多值索引也有一些功能限制。

  • 多值索引不能定义列的顺序 ASC 或 DESC,也不能用于消除排序,多值列不能用于主键。
EXPLAIN SELECT v_user FROM customers order by v_user;
EXPLAIN SELECT custinfo FROM customers2 order by custinfo;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/910553.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPAGA学习~问题记录

1.Error: concurrent assignmentto a non-netstart is not permitted(错误:不允许并发分配到非网络‘start’) 原因:wire 或reg 类型不匹配引起的,assign与wrie搭配使用,而reg一般在always、initial语句块中…

微服务系列四:热更新措施与配置共享

目录 前言 一、基于Nacos的管理中心整体方案 二、配置共享动态维护 2.1 分析哪些配置可拆,需要动态提供哪些参数 2.2 在nacos 分别创建共享配置 创建jdbc相关配置文件 创建日志相关配置文件 创建接口文档配置文件 2.3 拉取本地合并配置文件 2.3.1 拉取出现…

003-Kotlin界面开发之声明式编程范式

概念本源 在界面程序开发中,有两个非常典型的编程范式:命令式编程和声明式编程。命令式编程是指通过编写一系列命令来描述程序的运行逻辑,而声明式编程则是通过编写一系列声明来描述程序的状态。在命令式编程中,程序员需要关心程…

Python作业记录

复制过来的代码的换行有问题,但是也不是什么大问题。 后续我会进行补充和修改。 请将如下英文短句根据单词切分成列表: The continent of Antarctica is rising. It is due to a geological phenomenon called post-glacial uplift 并在切分好的列表…

pdmaner连接sqlexpress

别以为sqlserver默认的端口总是1433 案例 有台sqlserver2008 express服务器,刚安装,支持混合模式登录,其它什么配置也没改。 先看用ADO连接 这说明: 案例中sqlserver端口不是1433 !!!ADO连接…

轻型民用无人驾驶航空器安全操控------理论考试多旋翼部分笔记

官网:民用无人驾驶航空器综合管理平台 (caac.gov.cn) 说明:一是法规部分;二是多旋翼部分 本笔记全部来源于轻型民用无人驾驶航空器安全操控视频讲解平台 目录 官网:民用无人驾驶航空器综合管理平台 (caac.gov.cn) 一、轻型民用无人…

二叉树相关习题

题目:100. 相同的树 - 力扣(LeetCode) 给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。 示例 1: …

阅读笔记记录

论文作者将对话建模成一个seq2seq的映射问题,该seq2seq框架以对话历史数据(通过belief tracker建模)和数据库查询结果(通过Database Operator得到结果)作为支撑。 Abstract 教会机器完成与人自然交流的任务是充满挑战…

测试分层:减少对全链路回归依赖的探索!

引言:测试分层与全链路回归的挑战 在软件开发和测试过程中,全链路回归测试往往是一个复杂且耗费资源的环节,尤其在系统庞大且模块众多的场景下,全链路测试的集成难度显著提高。而“测试分层”作为一种结构化的测试方法&#xff0…

融合虚拟化与容器技术,打造灵活又安全的AI算力服务

随着人工智能技术的不断进步,AI企业在迅速推进大模型业务时,往往会倾向于采用容器化的轻量部署方案。相较于传统的虚拟机部署,容器化在快速部署、资源利用、环境一致性和自动化编排等方面具备显著优势。 然而,容器技术所固有的隔…

协程3 --- golang的协程调度

文章目录 单进程时代多进程/线程时代协程时代内核级线程模型(1:1)用户级线程模型(N:1)两级线程模型CMP(M:N)GM模型 GMP模型 单进程时代 描述:每一个程序就是一…

微服务透传日志traceId

问题 在微服务架构中,一次业务执行完可能需要跨多个服务,这个时候,我们想看到业务完整的日志信息,就要从各个服务中获取,即便是使用了ELK把日志收集到一起,但如果不做处理,也是无法完整把一次业…

【原创】java+ssm+mysql收纳培训网系统设计与实现

个人主页:程序猿小小杨 个人简介:从事开发多年,Java、Php、Python、前端开发均有涉猎 博客内容:Java项目实战、项目演示、技术分享 文末有作者名片,希望和大家一起共同进步,你只管努力,剩下的交…

apache poi 实现下拉框联动校验

apache poi 提供了 DataValidation​ 接口 让我们可以轻松实现 Excel 下拉框数据局校验。但是下拉框联动校验是无法直接通过 DataValidation ​实现,所以我们可以通过其他方式间接实现。 ‍ 步骤如下: 创建一个隐藏 sheet private static void create…

Linux权限概念 | 权限修改

文章目录 1.Linux的权限概念2.Linux权限管理3.文件访问权限的相关设置方法 1.Linux的权限概念 Linux下有两种用户:超级用户(root)和普通用户。对应root用户而言:可以在Linux系统下做任何事情,不受限制。而普通用户&am…

题目练习之二叉树那些事儿(续集)

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ 这一篇博客我们继…

删除MacOS下PowerPoint烦人的加载项

起因 最近要写论文,需要插入很多公式,利用自带的吧,太过繁琐,每次插入都需要点击插入-公式-符号,然后头脑发热想用下本科写论文时用过的MathType,结果这货现在要收费了,新版本只能适用30天&…

清华双臂机器人扩散大模型RDT:先预训练后微调,支持语言、图像、动作多种输入(1B参数)

前言 通过上文介绍的GR2,我们看到了视频生成模型在机器人训练中的应用 无独有偶,和GR2差不多一个时期出来的清华RDT,其模型架构便基于视频生成架构DiT改造而成(当然,该清华团队其实也在DiT之前推出了U-ViT,具体下文会…

Linux下GCC编译器的安装

Linux下GCC编译器的安装 以下所有的版本都可以在https://gcc.gnu.org/pub/gcc/infrastructure/这里找最新的 通过apt-get方式下载的Qt5.9的gcc编译器版本只是4.8.3,无法打开一些Qt5的库头文件,所以准备在Llinux下再安装一个gcc5.3.0。 查看gcc版本 ubu…