位运算在数据库中的运用实践-以MySQL和PG为例

目录

前言

一、两种不同的数据库设计

1、状态字段存储JSON

2、使用位运算

二、数据库中的位运算实践

1、MySQL中的位运算实践

2、PostgreSQL中位运算实践

三、总结


前言

        最近在解决某用户的一个业务需求时,遇到一个很有意思的场景。首先先跟大家分享一下需求背景。用户主要是面向一线的企业工厂,在他们实际生产过程中,为了保障安全生产。由于在车间中,所有的设备和机器都是全天运行,因此特别容易出现运行故障。因此,安全管理部门呢就结合生产时间,将组织专门的人员在上班时间内实现对运行设备的一个巡视,每个班组上班时间为8小时,同时要求每4个小时就要对设备进行一次巡查。根据上班时间分为早班、中班、晚班,每个班由1到多个人员组成。要求在他们上班后的一个小时内和快下班的一个小时内实现对目标设备的巡视,系统需要记录每次的检查记录,比如早班第一次和早班第二次等等。同时呢,在生产高峰期,由于订单的增加,有的机器运行更加频繁,因此要求加大巡视力度,巡视次数增加至四次,即两个小时巡视一次。同样要求系统记录不同次数的状态,一天巡查结束后,系统自动提供巡视结果,能反应出应巡的次数和漏巡的次数,工厂的管理班组将根据情况对相应的车间和安全管理人员进行考核和评价,纳入到月的的绩效考核当中,对于提早发现的故障信息,处置得当的给予奖励和奖金。

        以上就是大致的需求,其实刚开始拿到这个需求的时候,对于状态的记录到底用什么字段来存储,如何能达到快速保存状态和检索。比如可以快速的设置第一次和第二次的巡视状态为已完成。同时在查询时能快速查询第N次是否已完成等等操作。在实际业务中可有哪些选择来支持以上的需求,既能满足业务需求,也能较少技术的复杂度。

        这就是本文的理由,本文以一个实际的工厂日常检查工作的状态标记场景为例,首先讲解可以有哪些技术方案来实现上述需求,然后讲解表结构的设计,其次着重介绍位运算的表设计方式,以及位运算的处理方式,最后以MySQL和PostgreSQL为例介绍如何在这两个数据库中实现位运算,通过实际例子的讲解,让朋友理解位运算在数据库状态位的场景中的具体使用。通过本文,您可以掌握在面对状态标记时的数据库设计方法,如何在位运算中体现多次,如何操作位运算来设置值,以及如何快速查询定位等知识。

一、两种不同的数据库设计

        本节将根据拿到的用户初步需求,对需求进行分析,根据分析结果完成数据库的设计,同时具体阐述如何去进行表状态字段的更新和查询操作。设计没有好坏,根据不同的场景,有不同的应用。这里欢迎各位朋友进行讨论。由于在实际情况下,在上面的巡视工作中,根据不同的工作需求,每个组的巡视次数可能不固定的,所以这里要考虑实现次数的动态标记的需求。

1、状态字段存储JSON

        之所以考虑使用JSON的方式来进行存储,第一个考虑就是实现灵活的状态,如果是固定的次数,比如每个班就巡视两次,那么我们不妨设计出多个字段,比如早班第一次状态,早班第二次状态,一直到早班第N次,如果N有限,我们的字段尚且还可以设计出来,如果N是一个不固定的值,那么这种设计也是一种灾难。这里我想可能有朋友会说,多设计一些冗余字段是否可行,比如一次性设计8个字段出来。诚然,这种方案是没有大毛病,但是你想想这些问题,万一超了怎么办,还有就是一个班组8个字段,3个班组就是24个字段,光用来标记状态的字典就有24个,再加上其它的业务字段,这就是25+了,如此设计不仅浪费,同时查询性能也低,扩展性也不好。

        这个方式的改良办法就是将多字段改成JSON,通过JSON的存储来实现动态的次数,比如{“1”:0,“0”:1}用这样的字符串表示第一次已完成,第二次未完成。然后在查询的时候每次只需要进行json的关联查询即可,性能暂时还在可以接受的范围之内。你可以想想使用JSON存储值究竟有什么问题。

2、使用位运算

        其实在上面一节中已经大体讲了一下,在我们的业务中,我们只要顺序的记录每一次任务的执行状态,比如用0表示未完成,1表示已完成。0和1是二进制中最简单的表示,应用到应用程序中也是,使用他们来进行数据查询和检索,速度也是非常快的。而且也能实现动态的效果。比如,我们设计一个8位的二进制数,如下所示:

第8位第7位第6位第5位第4位第3位第2位第1位
00000000

        在上面的二进制数表示中,我们采用8位(可以根据实际情况增加长度)来表示对应次数的状态位,第一位表示第一次的状态,0表示未完成。在设计字段时,我们会将状态只设计成一个字段,它的值则有这8位二进制数转成对应的十进制数来表示,这样子不仅大大的减少了字段数,同时还能实现不同次数的状态分别记录。下面举个例子:

        第一次巡视已完成的二进制表示如下:

第8位第7位第6位第5位第4位第3位第2位第1位
00000001

        这里的第一位表示第一次为1,其它的仍为0,这是计算出来的二进制值是1。下面再来举一个例子,我们将第二次和第四次的状态设置为1,则8位的二进制表示如下:

第8位第7位第6位第5位第4位第3位第2位第1位
00001010

        此时,00001010这个数字换算成十进制的值为10,也就是十进制10表示二进制的00001010,表示该班组的第4次和第2次的巡视工作已完成,其它次数尚未完成。通过以上例子的讲解,您是否发现,使用位运算是否极大的简化了相关的数据库设计,也降低了数据的数据更新和检索的难度。因此我们在此情况下决定采用位运算的方式进行对应工作状态的标记。

二、数据库中的位运算实践

        前一节详细的介绍了我们选择的两种方案,也重点比较了两种方案的不同,优缺点也都进行了说明。当然,以上两种方案都可以实现业务需求,也能实现动态灵活的方案,但是相比于复杂度,我们选择位运算来实现。

        本节将结合MySQL和PostgreSQL数据库来分别详细讲解如何在这两个数据库中实现位运算,如何在这两个数据库中设置位运算结果和查询位状态。通过本节大家可以了解在MySQL和PostgreSQL数据库中熟练的进行位运算的操作。

1、MySQL中的位运算实践

        这里使用的MySQL的版本是5.7.14-x的版本,位运算是基础的计算,在更高级的版本中应该都是兼容的。本博客使用MySQL 5.7来做实验环境。

        查询MySQL版本,使用以下sql:

select VERSION();5.7.14-log

        我们首先来创建一张表,表仅用作演示,不代表实际的业务,实际的业务表还请各位朋友自己去设计。主要体现的位运算的处理过程,表的物理结构如下所示:

CREATE TABLE `example_table` (`id` INT AUTO_INCREMENT PRIMARY KEY,`status` INT NOT NULL DEFAULT 0
);

        表结构非常简单,只有两个字段,第一个字段是主键ID,设置位自增,而第二个字段为状态位,存储的值是十进制的表示数,请注意,这里的数据类型请结合具体的二进制状态位的计算过来定,int是一个非常大的数字了,用来存储是足够了,它的默认值用0表示,因为二进制8个0对应的十进制数也是0。

        首先我们查询一下表的数据,默认情况下,表里是没有数据的,需要我们手动插入数据,插入数据后的表数据如下:

select * from example_table;
idstatus
10
20
30
40
50
60
70

        下面我们来修改表记录的值,比如我们设置id为3的数据,第一次为1即标记已完成。sql语句如下:

-- 设置第N次为已完成 正确的做法
UPDATE example_table SET status = status | (1 << (N - 1)) WHERE id = 3;-- N表示具体的次数,即N=1
UPDATE example_table SET status = status | (1 << (1 - 1)) WHERE id = 3;

        在数据库客户端执行以下sql之后,客户端返回如下:

UPDATE example_table SET status = status | (1 << (1 - 1)) WHERE id = 3
> Affected rows: 1
> 时间: 0.089s

        表名id=3的这条记录已经发生了变更且更新成功。为了验证这个结果是不是二进制的正确表达呢?我们选择在数据库中进行进制转换的查询展示:

select *, CONCAT(REPEAT('0', 8 - CHAR_LENGTH(BIN(status))),BIN(status)) AS binary_status FROM example_table ;

        这里用到的函数有三个,最里面的是bin函数,表示将值转为二进制,然后用char_length函数求出转换出来的二进制数长度,再repeat函数和concat函数,最终拼成一个二进制字符串的表示,总的长度为8位,如果位数不足,则在前面补0,比如十进制0,二进制表达为:00000000。十进制1,二进制表示位:00000001。在客户端中执行以上的sql后可以在返回的结果中看到如下:

idstatusbinary_status
1000000000
2000000000
3100000001
4000000000
5900001001
6000000000
7000000000

        到这里,我们已经实现了状态位运算的动态更新,比如指定第几位为1,那么与之对应的另一个问题就是,如何查询出第几位为已完成。同样的我们也还是需要使用位运算,计算的方法如下:

-- 查询第N次是否完成,N表示第几次
select *, CONCAT(REPEAT('0', 8 - CHAR_LENGTH(BIN(status))),BIN(status)) AS binary_status FROM example_table 
WHERE (status & (1 << (N - 1))) > 0 ;-- 查询第N次是否完成,1表示第1次即N=1
select *, CONCAT(REPEAT('0', 8 - CHAR_LENGTH(BIN(status))),BIN(status)) AS binary_status FROM example_table 
WHERE (status & (1 << (1 - 1))) > 0 ;

        上述查询的结果如下:

idstatusbinary_status
3100000001
5900001001

        到此,关于如何在MySQL中进行位运算的设置以及查询的效果演示就到此结束,关于其它的位运算可以参考其它网页的资料。

2、PostgreSQL中位运算实践

        在讲解了位运算在MySQL中的应用之后,下面也来讲讲在PG的运用。其实位运算在SQL中的运用效果是差不多的,MySQL和PG的位运算过程效果差别不大,为什么这里还要拿出来讲呢?主要是在PG中,要想实现二进制字符串的展示不太直观,这里分享一种在PG中的处理方式,供大家参考。

        本文使用的PG版本如下:

        查询sql:SELECT version(); 执行后查询结果如下:

PostgreSQL 12.3, compiled by Visual C++ build 1914, 64-bit

        与MySQL一样的,为了演示上述的效果,我们依然创建一张Pg的表,相关DDL语言稍微有点区别:

CREATE TABLE "public"."example_table" ("id" int8 NOT NULL,"status" int4,CONSTRAINT "example_table_pkey" PRIMARY KEY ("id")
);

        在PG中设置第N次为已完成即为1的sql语句与MySQL是一致的,如下:

-- 设置第N次为已完成 正确的做法
UPDATE example_table SET status = status | (1 << (N - 1)) WHERE id = 6;

        这里有小伙伴会问,上面的SQL是设置为已完成,那么重置为0应该怎么实现呢?可以使用下面的sql来实现:

-- 设置第几次为0
UPDATE example_table SET status = status & (~(1 << (N - 1))) WHERE  id = 5;

        在PG数据库中,直接将二进制转换为十进制的字符串的方法没有,因此我们不能直接使用内置函数来完成,需要使用自定义函数的方式,自定义函数的逻辑与MySQL差不多,整体长度是8,不够的位数用0来补齐。函数的实现如下:

CREATE OR REPLACE FUNCTION "public"."decimal_to_binary_string"("num" int8)RETURNS "pg_catalog"."text" AS $BODY$DECLARE  binary_str TEXT := '';  temp_num BIGINT := num;  
BEGIN  WHILE temp_num > 0 LOOP  -- 使用模2运算来获取最低位的二进制值  binary_str := CAST(temp_num % 2 AS TEXT) || binary_str;  -- 使用整除2来去掉已经处理的最低位  temp_num := temp_num / 2;  END LOOP;  -- 如果输入为0,则直接返回'0'  IF binary_str = '' THEN  binary_str := '0';  END IF;  RETURN binary_str;  
END;  $BODY$LANGUAGE plpgsql VOLATILECOST 100

        在创建好以上的转换函数之后,在数据库中执行以下SQL:

select *, LPAD(decimal_to_binary_string(status), 8, '0') AS binary_status FROM example_table
order by id;

        查询结果如下:

idstatusbinary_status
1000000000
2000000000
3000000000
4000000000
5000000000

        到此,我们将如何在PG中实现位运算进行了详细的说明。

三、总结

        以上就是本文的主要内容,本文以一个实际的工厂日常检查工作的状态标记场景为例,首先讲解可以有哪些技术方案来实现上述需求,然后讲解表结构的设计,其次着重介绍位运算的表设计方式,以及位运算的处理方式,最后以MySQL和PostgreSQL为例介绍如何在这两个数据库中实现位运算,通过实际例子的讲解,让朋友理解位运算在数据库状态位的场景中的具体使用。通过本文,您可以掌握在面对状态标记时的数据库设计方法,如何在位运算中体现多次,如何操作位运算来设置值,以及如何快速查询定位等知识。行文仓促,难免有不足之处,如果有不足之处,还请各位专家朋友在评论区不吝赐教,不甚感激。

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

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

相关文章

飞腾平台虚拟机组播性能调优指南

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力&#xff0c;聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域&#xff0c;包含了应用使能套件、软件仓库、软件支持、软件适…

STM32G4 DMA的使用(寄存器开发)

下面以STM32G474为例&#xff0c;使用DMA来存储USART1的接收数据。 1. 查看硬件支持 首先查看要使用的DMA支持的通道数&#xff0c;在手册中有如下说明。 根据上图可以看到&#xff0c;对于不同的设备类型有不同的DMA通道数量。设备类型分类如下图所示。 我使用的是STM32G474…

基于 TI AM62 测试 QtWayland 部署

By Toradex秦海 1). 简介 目前主流的 ARM 平台嵌入式 Linux BSP 的显示后端基本都已经从 X11 升级到了 Wayland&#xff0c; 而常用的 Wayland Compositor - Weston 对于 Linux 下常用的 Qt 图形界面开发框架的一些 Plugin (比如 Qt VirtualKeyboard) 的配合并不完善&#xf…

什么是边缘计算?创造一个更快、更智慧、更互联的世界

前言 如今&#xff0c;数十亿物联网传感器广泛部署在零售商店、城市街道、仓库和医院等各种场所&#xff0c;正在生成大量数据。从这些数据中更快地获得洞察&#xff0c;意味着可以改善服务、简化运营&#xff0c;甚至挽救生命。但要做到这一点&#xff0c;企业需要实时做出决策…

tableau标靶图,甘特图与瀑布图绘制 - 9

标靶图&#xff0c;甘特图与瀑布图 1. 标靶图绘制1.1 筛选器筛选日期1.2 条形图绘制1.3 编辑参考线1.4 设置参考线1.5 设置参考区间1.6 四分位设置1.7 其他标靶图结果显示 2.甘特图绘制2.1 选择列属性2.2 选择列属性2.3 创建新字段2.4 设置天数大小及颜色 3. 瀑布图绘制3.1 she…

【pytorch20】多分类问题

网络结构以及示例 该网络的输出不是一层或两层的&#xff0c;而是一个十层的代表有十分类 新建三个线性层&#xff0c;每个线性层都有w和b的tensor 首先输入维度是784&#xff0c;第一个维度是ch_out,第二个维度才是ch_in(由于后面要转置)&#xff0c;没有经过softmax函数和…

【利用GroundingDINO裁剪分类任务的数据集】及文本提示检测图像任意目标(Grounding DINO) 的使用

文章目录 背景1.Grounding DINO安装2.裁剪指定目标的脚本 背景 在处理公开数据集ImageNet-21k的时候发现里面有很多的数据有问题&#xff0c;比如&#xff0c;数据目标有很多背景&#xff0c;且部分类别有其他种类的图片。针对数据目标有很多背景&#xff0c;公开数据集ImageNe…

【数据库】Redis主从复制、哨兵模式、集群

目录 一、Redis的主从复制 1.1 主从复制的架构 1.2 主从复制的作用 1.3 注意事项 1.4 主从复制用到的命令 1.5 主从复制流程 1.6 主从复制实现 1.7 结束主从复制 1.8 主从复制优化配置 二、哨兵模式 2.1 哨兵模式原理 2.2 哨兵的三个定时任务 2.3 哨兵的结构 2.4 哨…

ArkUI开发学习随机——B站视频简介页面,美团购买界面

案例一&#xff1a;B站视频简介页面 代码&#xff1a; build() {Column(){Column(){Stack(){Image($r("app.media.genimpact")).width(200).height(125).borderRadius({topLeft:5,topRight:5})Row(){Image($r("app.media.bz_play")).height(24).fillColor…

【人工智能】Transformers之Pipeline(概述):30w+大模型极简应用

​​​​​​​ 目录 一、引言 二、pipeline库 2.1 概述 2.2 使用task实例化pipeline对象 2.2.1 基于task实例化“自动语音识别” 2.2.2 task列表 2.2.3 task默认模型 2.3 使用model实例化pipeline对象 2.3.1 基于model实例化“自动语音识别” 2.3.2 查看model与task…

IEC62056标准体系简介-4.IEC62056-53 COSEM应用层

为在通信介质中传输COSEM对象模型&#xff0c;IEC62056参照OSI参考模型&#xff0c;制定了简化的三层通信模型&#xff0c;包括应用层、数据链路层&#xff08;或中间协议层&#xff09;和物理层&#xff0c;如图6所示。COSEM应用层完成对COSEM对象的属性和方法的访问&#xff…

01MFC建立单个文件类型——画线

文章目录 选择模式初始化文件作用解析各初始化文件解析类导向创建鼠标按键按下抬起操作函数添加一个变量记录起始位置注意事项代码实现效果图虚实/颜色线选择模式 初始化文件作用解析 运行: 各初始化文件解析 MFC(Microsoft Foundation Classes)是一个C++类库,用于在Win…

防御课综合实验

实验拓扑&#xff1a; 实验要求&#xff1a; 1、DMZ区内的服务器&#xff0c;办公区仅能在办公时间内&#xff08;9点到18点&#xff09;可以访问&#xff0c;生产区的设备全天可以访问 2、生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3、办公区设备10…

二叉平衡树(左单旋,右单旋,左右双旋、右左双旋)

一、AVL树&#xff08;二叉平衡树&#xff1a;高度平衡的二叉搜索树&#xff09; 0、二叉平衡树 左右子树高度差不超过1的二叉搜索树。 public class AVLTree{static class AVLTreeNode {public TreeNode left null; // 节点的左孩子public TreeNode right null; // 节点的…

基于Transformer的端到端的目标检测 | 读论文

本文正在参加 人工智能创作者扶持计划 提及到计算机视觉的目标检测&#xff0c;我们一般会最先想到卷积神经网络&#xff08;CNN&#xff09;&#xff0c;因为这算是目标检测领域的开山之作了&#xff0c;在很长的一段时间里人们都折服于卷积神经网络在图像处理领域的优势&…

论文 | REACT: SYNERGIZING REASONING AND ACTING INLANGUAGE MODELS

本文首先认为&#xff0c;到目前为止&#xff0c;LLM 在语言理解方面令人印象深刻&#xff0c;它们已被用来生成 CoT&#xff08;思想链&#xff09;来解决一些问题&#xff0c;它们也被用于执行和计划生成。 尽管这两者是分开研究的&#xff0c;但本文旨在以交错的方式将推理…

JSP入门基础

JSP入门基础 软件开发环境这门课程的复习资料 Web开发技术概述 URL的组成部分 协议、主机DNS名或IP地址和文件名 Tomcat服务器 Tomcat服务器的默认端口号是8080 概念 软件开发环境是围绕着软件开发的一定目标而组织在一起的一组相关软件工具的有机集合 JSP和HTML的区别…

SPE连接器技术革新汽车制造业

概述 新的SPE标准在汽车制造业中的应用正日益受到重视&#xff0c;它不仅推动了汽车通信技术的革新&#xff0c;还对汽车性能测试方法产生了深远影响。本文将详细探讨SPE标准在汽车制造业中的应用案例分析&#xff0c;以及它对供应链的挑战与机遇。 SPE标准在汽车制造业中的应…

[leetcode]subarray-product-less-than-k 乘积小于K的子数组

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int numSubarrayProductLessThanK(vector<int>& nums, int k) {if (k 0) {return 0;}int n nums.size();vector<double> logPrefix(n 1);for (int i 0; i < n; i) {logPrefix[i 1] …

揭秘!chatGPT核心技术应用

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT-3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年11月7日&#xff0c;OpenAI首届开发者大会被称为“科技界的春晚”&#xff0c;吸引了全球广大…