MySQL的Json类型字段IN查询分组和优化方法

news2025/1/26 15:41:00

前言 

       MySQL从5.7的版本开始支持Json后,我时常在设计表格时习惯性地添加一个Json类型字段,用做列的冗余。毕竟Json的非结构性,存储数据更灵活,比如接口请求记录用于存储请求参数,因为每个接口入参不一致,也有不传和空传的等等。

        然而在一些特定场景下,需要用Json字段里的某个键用来In查询,并且需要保证不会造成慢查询的前提下,用该键对整个查询结果分组。因为这张表属于是高频储存的表,数据相对庞大,下面先看看SQL查询和放到业务里的查询时间。

场景介绍

        数据表主要存储来自客户端的请求信息,如客户端标识,接口名,渠道,来源,IP,入参等等。而场景是需要对某个页面下某个物品的请求总数和请求用户数,也就是要将访问数和访问用户数作为字段字段方式拼接到物品上。到这里可能很多人会说,在指定页埋点计数式更新物品两个字段就可以了,干嘛这么麻烦去明细表里统计。

        如此的做法,就真的是因为懒,毕竟有时功能不是很重要就没必要为此多创建一张与库里有重叠性质的表,下次去掉这部分时,多一张给后来者新增一份负担,看着没用的表又不敢删。好了扯远了,下面就开始用SQL和业务代码测试查询效果和后面优化方法吧。

SQL查询

SELECT json_extract(params,'$.item_id') as item_id, count(id), page_name, params, COUNT(DISTINCT cookie_md5) FROM `temp_record` WHERE  `page_name` IN ('api/GoodsItem/read','api/GoodsItem/readnew','api/GoodsItem/details')  AND ( params->'$.item_id' in (40349,40348,40347,40346,40345,40342,40341,40340,40334,40333,40332,40331,40330,40328,40327,40326,40325,40324,40323,40322,40321,40320,40319,40318,40317,40316,40315,40314,40313,40312,40311,40310,40309,40308,40307,40306,40305,40304,40303,40302,40298,40297,40296,40295,40294,40293,40292,40291,40290,40289) )
GROUP BY (params->'$.item_id')

    当前数据量不多的情况下,查询时间0.56秒,针对条件我先对其中一个字段添加了NORMAL类型索引后,查询时间在0.07和0.19间跳动。虽然速度提升了一点,但是这里还有一个关键的查询,就是Json里的item_id的键,既作为条件又作为分组参。

    但是索引只能使用字段,Json字段里的键是不可能加进去的。虽然但是有一种曲线设置的方式,就是提取Json里的item_id为一个虚拟字段,然后将该虚拟字段设置为索引,于是就开始操作了。

优化方法

1. 图形创建虚拟字段

以下用Navicat for MySQL为例,新建字段,勾选 “虚拟”, 虚拟类型 “VIRTUAL”, 表达式 cast(json_extract(`params`,'$.item_id') as signed),也就是从Json提取“item_id”。

2. 命令创建虚拟字段

ALTER TABLE `temp_record`
	ADD COLUMN `item_id` int(11) GENERATED ALWAYS AS (cast(json_extract(`params`,'$.item_id') as signed));

3. 设置索引

进入设置,像添加普通字段的方式将item_id设置为普通索引。

4. 优化查询结果

SELECT item_id, count(id), page_name, params, COUNT(DISTINCT cookie_md5) FROM `temp_record` WHERE  `page_name` IN ('api/GoodsItem/read','api/GoodsItem/readnew','api/GoodsItem/details')  AND ( item_id in (40349,40348,40347,40346,40345,40342,40341,40340,40334,40333,40332,40331,40330,40328,40327,40326,40325,40324,40323,40322,40321,40320,40319,40318,40317,40316,40315,40314,40313,40312,40311,40310,40309,40308,40307,40306,40305,40304,40303,40302,40298,40297,40296,40295,40294,40293,40292,40291,40290,40289) )
GROUP BY (params->'$.item_id')

修改后,查询时间稳定在0.05秒上下一点,可以说相较之前是快了10倍,分组中其实也是可以改成item,但是数据里有字符串的item_id索引为了兼容这种类型,分组还是用的JSON取值方式,速度影响不大。

PHP代码

1. 统计(仅作参考)

public static function clickCount($goodsItemIds = [])
{
	$pageName = [
		'api/GoodsItem/read',
		'api/GoodsItem/readnew',
		'api/GoodsItem/details'
	];
	$goodsItemIds = implode(",", $goodsItemIds);

	$where[] = ['page_name', 'in', $pageName];
	//$where[] = ['params->item_id', 'in', $goodsItemIds];

	$data = Db::name('temp_record')->field("item_id,count(id) as pv, count(DISTINCT cookie_md5) as uv")
		->where($where)->whereRaw("params->'$.item_id' in ($goodsItemIds)")->group("params->item_id")
		->select();

	$data && $data = array_column($data, null, 'item_id');

	return $data;
}

2. 明细(仅作参考)

public static function clickRecord($itemId = 0, $page = 1, $size = 20)
{
	$result['count'] = 0;
	$result['list'] = [];

	$pageName = [
		'api/GoodsItem/read',
		'api/GoodsItem/readnew',
		'api/GoodsItem/details'
	];

	$where[] = ['page_name', 'in', $pageName];

	$field = ["from_unixtime(day_time, '%Y-%m-%d') as day_time, count(id) as clicks,
	count(DISTINCT cookie_md5) as user_clicks"];

	$result['list'] = Db::name('temp_record')
		->field($field)
		->where($where)->whereRaw("params->'$.item_id' = $itemId")
		->group("day_time")
		->page($page, $size)
		->order('day_time desc')
		->select();

	$result['count'] = Db::name('temp_record')->field($field)->where($where)
		->whereRaw("params->'$.item_id' = $itemId")->group("day_time")->count();

	return $result;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python的交互式库Qgrid

目录 Qgrid介绍Qgrid使用Qgrid使用过程中遇到的问题解决方案 Qgrid介绍 在Jupyter notebook中直接读取DataFrame数据,只显示为静态表格的形式,没有类似于excel的筛选等交互式功能。Qgrid作为 Jupyter notebook 组件,可以为我们的 DataFrame …

三本书与三场发布会,和鲸社区重新定义编程类书籍从阅读到实践新体验

当 AI 开发者社区配备 AI 基础设施开发平台工具时,它还能做什么? 答案是:过去半年,和鲸社区凭借在气象、医学、社科等垂直领域的长期积累以及多方伙伴的支持,联合举办了三场新书发布会——从 Python 到 R 语言 、从气…

程序员与ChatGPT的交织:探索人工智能和软件开发的新篇章

目录 前言创作者程序员会被替代吗程序员如何更好的使用chatgpt 前言 在技术持续进步的当今世界,程序员与人工智能(AI)之间的关系越来越紧密。特别是对于一些创新性的技术如OpenAI旗下的ChatGPT,这种联系就更为明显。程序员与Chat…

2023/8/16 华为云OCR识别驾驶证、行驶证

目录 一、 注册华为云账号开通识别驾驶证、行驶证服务 二、编写配置文件 2.1、配置秘钥 2.2、 编写配置工具类 三、接口测试 3.1、测试接口 3.2、结果 四、实际工作中遇到的问题 4.1、前端传值问题 4.2、后端获取数据问题 4.3、使用openfeign调用接口报错 4.3、前端显示问题…

python bytes基本用法

目录 1 第一个字符变大写,其余字符变小写 capitalize() 2 生成指定长度内容,然后把指定的bytes放到中间 center() 3 计数 count() 4 解码 decode() 5 是否以指定的内容结尾 endswith() 6 将制表符调整到指定大小 expandtabs() 7 寻找指…

ref拿到组件的实例对象或者原生html标签

在组件中,或者html标签中写ref属性,就是在注册引用 可以通过ref拿到组件的实例对象 也可以通过ref拿到原生的html标签

Linux系统安装及使用HHDBCS

1 安装 1.1 下载HHDBCS 使用浏览器进入官方社区(恒辉产品社区),选择HHDBCS子社区,首页点击下载,进入下载页面; 选择官网下载/云盘下载皆可。 在弹出框中选择如图所示选项,点击下载&#xff…

带着设计思维画版图——第一次和第二次

版图设计目标: 面积小,性能好(少恶化),成本低 设计规则规定了同层与不同层之间的最小距离,因此限制了最小面积 模拟版图设计流程 第一步:设计原理图输入 常用快捷键如下: 介…

YOLO算法封装进入ros系统,识别结果供其他节点订阅

一,前期工作空间搭建 新建工作空间,第一级名称可以换,第二级src最好别换,这是ros系统的固定格式 mkdir -p workspace_yolo/src切换到工作空间 workspace_yolo,进行编译构建项目 cd workspace_yolo/catkin_make输出如下所示: 添加环境变量 cd devel/ 获取到devel文件路径…

模型预测笔记(一):数据清洗分析及可视化、模型搭建、模型训练和预测代码一体化和对应结果展示(可作为baseline)

模型预测 一、导入关键包二、如何载入、分析和保存文件三、修改缺失值3.1 众数3.2 平均值3.3 中位数3.4 0填充 四、修改异常值4.1 删除4.2 替换 五、数据绘图分析5.1 饼状图5.1.1 绘制某一特征的数值情况(二分类) 5.2 柱状图5.2.1 单特征与目标特征之间的…

花生十三 判断推理(三)分析类、推出类

分析类 题型 真假分析 定义:孰真孰假的真假话分析,命题真假无法确定,无法利用推出关系解题 解题思路 矛盾法(三种矛盾):A和非A,“A或B” 与“非A且非B” 技巧:一“找”矛盾&am…

在ARM服务器上一键安装Proxmox VE(以在Oracle Cloud VPS上为例)(甲骨文)

前言 如题,具体用到的说明文档如下 virt.spiritlhl.net 具体流程 首先是按照说明,先得看看自己的服务器符不符合安装 Proxmox VE的条件 https://virt.spiritlhl.net/guide/pve_precheck.html#%E5%90%84%E7%A7%8D%E8%A6%81%E6%B1%82 有提到硬件和软…

C# 读取pcd、ply点云文件数据

最近研究了下用pcl读取点云数据,又做了个C#的dll,方便读取,同样这个dll基于pcl 最新版本1.13.1版本开发。 上次做的需要先得到点云长度,再获取数据。这次这个定义了一个PointCloudXYZ类来存数据。将下面的dll拷贝到可执行目录下&a…

边缘网络的作用及管理工具

自从引入软件即服务 (SaaS) 以来,它一直引领着全球按需软件部署创新的竞赛,它提供的灵活性以及其云计算架构带来的易于集成使其成为交付业务应用程序的标准。 在 SaaS 模型中,最佳用户体验的三重奏涉及无缝设置、低延…

20230818 数据库自整理部分

并发事务 脏读 一个事务读取到另一事务还没有提交的数据 事务B读取了事务A还没有提交的数据 不可重复读 一个事务先后读取同一条记录,但是两次读取的数据不同,称之为不可重复读 查询出来的数据不一样 1步骤b还没有提交 3步骤b已经提交 幻读 一个…

利用dayj转换查询时间获取当前周月年最后一天

利用dayj转换查询时间 queryForm 查询参数对象 switch 区分选择时间类型 日 周 月 年 计算结束时间 dayjs(element).endOf("week").format("YYYY-MM-DD") 当前周结束时间 日期时间查询框配置参数格式 {label: "",width: 220,key: "…

中期国际:MT4挂单和止损设置教程:善用限价和止损单来管理风险

在外汇交易中,合理设置挂单和止损是保护资金和管理风险的重要手段。MT4平台提供了便捷的挂单和止损功能,帮助交易者更好地控制交易风险。本文将为您介绍如何善用限价和止损单来管理风险,以及在MT4平台上的操作步骤。 一、设置限价挂单 限价挂…

ZooKeeper单机服务器启动

ZooKeeper服务器的启动,大体可以分为以下五个主要步骤:配置文件解析、初始化数据管理器、初始化网络I/O管理器、数据恢复和对外服务。下图所示是单机版ZooKeeper服务器的启动流程图。 预启动 预启动的步骤如下。 (1)统一由QuorumPeerMain作为启动类。 …

游乐场vr设备虚拟游乐园vr项目沉浸体验馆

在景区建设一个VR游乐场项目可以为游客提供一种新颖、刺激和沉浸式的游乐体验。提高游客的体验类型,以及景区的类目,从而可以吸引更多的人来体验。 1、市场调研:在决定建设VR游乐场项目之前,需要进行市场调研,了解当地…

YOLOv2和YOLOv3基础

目录 v2改进网络结构先验框感受野 V3多scale残差网络架构先验框softmax层代替 v2 改进 网络结构 先验框 感受野 V3 多scale 残差 网络架构 先验框 softmax层代替