Mysql 数据库中设备实时状态表水平分表

一、 需求概述

在使用 Mysql 数据库存储设备上报日志时,存在一张设备实时状态表,随着时间推移,数据量变得十分庞大。为了更好地管理和查询数据,提高数据库性能,需要对该表进行水平分表操作。同时,存在分页查询的需求,不过仅在针对单个设备状态查询时才需要分页展示结果,以方便查看设备在不同时间段的状态信息,避免一次性返回大量数据影响性能和使用体验。

二、分表键的选择策略详解

1. 哈希取模分片

哈希取模分片是常用的水平分表策略,通过对选定的分片键(如设备编号)进行哈希运算后取模,确定数据存储的分表。

  • 原理及优势

    • 均匀分布数据:对于设备实时状态表这种大数据量且设备众多的情况,能让数据均匀分散到各分表。例如,假设有 10 张分表,对设备编号哈希取模 10,不同设备的状态日志可均衡落入这 10 张表,避免数据倾斜,使各表数据量相近,查询时各分表负载均衡,提升数据库整体性能。
    • 简单高效的路由:查询时按相同哈希取模规则,可快速定位对应分表。比如查询某个设备状态日志,经设备编号哈希取模运算,就能知晓去哪个分表获取数据,减少全表扫描和复杂查找逻辑,尤其适用于单个设备状态查询场景。
  • 缺点及注意事项

    • 扩容复杂:业务发展需增加分表数量时(如从 10 张扩到 20 张),哈希取模规则改变,原本数据分布打乱,需进行数据迁移来重新平衡各表数据,操作复杂耗时,涉及大量数据读写和系统调整,所以规划分表数量初期要考虑未来业务增长规模,预留扩展空间。
    • 哈希冲突:虽然哈希算法通常能保证唯一性,但理论上存在不同设备编号哈希计算后结果相同(取模后也相同)的情况,即哈希冲突。不过实际应用中,选择合适哈希函数(如 MD5、SHA 等或数据库自带算法)可将冲突概率降至极低,开发人员仍需在代码中考虑应对冲突,比如增加额外处理逻辑区分冲突记录。

例如,在 Spring Boot + MyBatis 手动分表时,按以下代码逻辑实现哈希取模确定分表(以设备编号后三位数字简单取模为例,实际可采用更严谨算法):

public class TableShardingUtil {private static final int TABLE_COUNT = 10;  // 假设分表数量为 10public static String getTableNameByDeviceId(String deviceId) {int deviceIdSuffix = Integer.parseInt(deviceId.substring(deviceId.length() - 3));  // 获取设备编号后三位并转为整数int tableIndex = deviceIdSuffix % TABLE_COUNT;  // 取模确定分表索引return "device_status_" + String.format("%03d", tableIndex);  // 构建分表名,格式化为三位数字,如 device_status_001}
}

在 MyBatis 的 SQL 语句中利用该方法构建动态表名(XML 映射文件中):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.DeviceStatusMapper"><select id="getDeviceStatusByDeviceIdPage" resultMap="DeviceStatusResultMap">SELECT * FROM #{tableName}  <!-- 这里使用动态表名 -->WHERE device_id = #{deviceId}LIMIT #{offset}, #{limit}</select>
</mapper>

对应的 Mapper 接口方法传入计算得到的表名:

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;@Mapper
public interface DeviceStatusMapper {List<DeviceStatus> getDeviceStatusByDeviceIdPage(@Param("tableName") String tableName,  // 新增表名参数@Param("deviceId") String deviceId,@Param("offset") int offset,@Param("limit") int limit);
}

业务逻辑层调用时先算出表名再传递给 Mapper 方法查询:

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;@Service
public class DeviceStatusService {@Resourceprivate DeviceStatusMapper deviceStatusMapper;public List<DeviceStatus> getDeviceStatusByDeviceIdPage(String deviceId, int pageNum, int pageSize) {String tableName = TableShardingUtil.getTableNameByDeviceId(deviceId);int offset = (pageNum - 1) * pageSize;return deviceStatusMapper.getDeviceStatusByDeviceIdPage(tableName, deviceId, offset, pageSize);}
}

通过这种方式实现基于哈希取模的分片键策略,动态依据设备编号确定分表并进行分页查询操作。

2. 范围分片
  • 原理及优势

    • 按业务逻辑自然划分:依据数据的某个范围属性来划分分表,像按时间范围(如按天、月、年等)对设备实时状态表分表就是典型的范围分片。这种方式契合按时间段查询数据的业务习惯,查询特定时间段内设备状态日志时,可直接定位对应时间范围分表,减少不必要数据检索,提高查询效率,且对基于时间序列的数据分析、历史数据归档等操作更便捷,数据组织形式直观易懂。
    • 易于数据管理和维护:进行数据清理、备份等操作时,基于范围分片能按时间等范围属性方便地批量处理分表数据,比如定期清理久远时间范围分表中的过期数据,不影响其他活跃时间段的数据表。
  • 缺点及注意事项

    • 可能出现数据倾斜:若业务数据在某些范围内分布不均,易导致数据倾斜。比如某些时间段设备上报状态日志多,有些时间段少,对应的分表数据量差异大,查询时各分表负载不均衡,影响整体性能。所以选择范围分片时,要充分考虑业务数据在该范围属性上的分布特点,必要时结合其他策略缓解数据倾斜,如细分范围或配合哈希取模均匀分布数据。
    • 跨表查询需求处理复杂:涉及跨越多个范围分表查询(如查询一个设备较长时间跨度内状态,跨越多个月分表)时,需编写复杂查询逻辑整合多表数据,不像单表查询简单直接,要特别注意处理分表连接、数据去重等问题,避免数据不一致或查询结果不准确。
3. 一致性哈希分片
  • 原理及优势

    • 数据分布相对稳定:一致性哈希是特殊哈希算法,面对节点(分表可看作节点)增减时,相比普通哈希取模,能最大程度减少数据迁移量。例如在分布式数据库环境中,新增或减少分表数量时,一致性哈希可保证只有少部分数据需重新分配到新分表,使数据分布在动态变化场景下保持相对稳定,减少对业务影响。
    • 可扩展性较好:对于业务发展、数据量增长需不断扩充分表的情况,一致性哈希分片能更平滑适应变化,降低分表扩展带来的运维成本和数据调整难度,提高系统整体可扩展性,更利于应对复杂多变的业务需求。
  • 缺点及注意事项

    • 实现相对复杂:一致性哈希算法原理和实现比普通哈希取模复杂,要求开发人员有更深入理解和专业编程能力进行代码实现与部署,增加开发和维护难度。在一些对可扩展性要求不高的简单应用场景,使用一致性哈希可能增加不必要复杂度。
    • 存在数据倾斜风险:虽然一致性哈希能一定程度均匀分配数据,但在极端情况(如节点分布不均或数据哈希值分布有偏差)下,也可能出现数据倾斜,导致部分分表负载过重,影响查询性能,实际应用中需关注数据分布并适当优化。

三、水平分表及分页查询实现示例

(一)数据库表结构设计

1.设备实时状态表结构(分表前)

假设设备上报的日志主要包含设备的基本信息、状态信息以及上报时间等内容,以下是一个简单的表结构设计示例:

字段名类型说明是否可空主键
idbigint自增唯一标识,每条日志记录的唯一编号
device_idvarchar(50)设备编号,用于唯一标识每一台设备
device_namevarchar(100)设备名称,方便直观了解设备情况
status_codeint设备状态码,不同数值代表不同的运行状态,例如 0 表示正常,1 表示故障等
status_detailtext设备状态详细描述,比如故障具体原因等信息
report_timedatetime设备上报该状态的时间
other_infovarchar(255)其他可能的补充信息,如设备所在位置等(可根据实际情况扩展)

在这个表结构中,id 作为主键保证每条记录的唯一性,便于数据的索引和管理。而 device_id 是区分不同设备的关键字段,后续水平分表就会基于它来进行操作,report_time 用于记录状态上报的时间点,方便后续按时间维度查询和分析设备状态变化情况等。

2.分表后的表结构

根据 device_id 作为分表键进行水平分表,分表后的每张表结构与原始表结构基本一致,只是数据根据分表规则分散到了不同的表中。

例如,假设按照设备编号对 10 取模的方式将数据分到 10 张表中,表名可以分别命名为 device_status_0device_status_1device_status_2…… device_status_9

device_status_0 为例,其表结构如下:

字段名类型说明是否可空主键
idbigint自增唯一标识,每条日志记录的唯一编号
device_idvarchar(50)设备编号,用于唯一标识每一台设备
device_namevarchar(100)设备名称,方便直观了解设备情况
status_codeint设备状态码,不同数值代表不同的运行状态,例如 0 表示正常,1 表示故障等
status_detailtext设备状态详细描述,比如故障具体原因等信息
report_timedatetime设备上报该状态的时间
other_infovarchar(255)其他可能的补充信息,如设备所在位置等(可根据实际情况扩展)

其他 device_status_1device_status_9 等表结构均与之相同,只是每张表中存储的数据是根据 device_id 取模规则分配过来的对应设备的状态日志信息。

(二)使用 springboot + mybatis 手动水平分表并实现分页

  1. 分表设计
    首先要确定分表键,对于设备实时状态表来说,设备编号(device_id)是比较合适的分表键选择。因为往往是针对单个设备的操作和查询较多,以设备编号进行分表能让同一设备的数据集中存储在一张分表中,方便后续查询和管理。可以按照一定规则,比如根据设备编号对分表数量取模的方式,将数据均匀分散到不同的分表中,例如有 10 张分表,设备编号为 1001 的设备,通过 1001 % 10 确定其存储在对应的分表中。
  2. 代码实现
    在 Spring Boot 项目中,配置好 MyBatis 相关依赖和数据库连接信息。创建针对不同分表的 Mapper 接口和对应的 XML 映射文件。在查询单个设备状态并分页时,需要在 Mapper 接口中定义相应的方法,例如:
List<DeviceStatus> getDeviceStatusByPage(@Param("deviceId") String deviceId, @Param("offset") int offset, @Param("limit") int limit);

在 XML 映射文件中编写 SQL 语句,通过传入的设备编号确定要查询的分表,结合传入的偏移量(offset)和每页数量(limit)来实现分页查询,示例 SQL 如下:

SELECT * FROM device_status_${deviceId % 10} 
WHERE device_id = #{deviceId} 
LIMIT #{offset}, #{limit};

在 Service 层调用该 Mapper 方法,传入相应参数即可实现单个设备状态的分页查询,通过这种手动方式灵活控制分表和分页逻辑,但需要自行处理较多的细节,如分表规则的维护等。

(三)使用 springboot + sharing-jdbc + mybatis 实现水平分表并分页查询

  1. 分表配置
    同样选择设备编号(device_id)作为分表键。在 Spring Boot 项目中引入 Sharding-JDBC 相关依赖,然后通过配置文件(如 application.yml)进行分表规则配置。例如:
sharding:tables:device_status:actual-data-nodes: device_status_$->{0..9}.device_statustable-strategy:inline:sharding-column: device_idalgorithm-expression: device_status_$->{device_id % 10}

这样 Sharding-JDBC 会按照配置的规则自动根据设备编号对数据进行分表存储。
2. 分页查询实现
在 MyBatis 的 Mapper 接口中定义查询方法,和上面类似,例如:

List<DeviceStatus> getDeviceStatusByPageWithSharding(@Param("deviceId") String deviceId, @Param("offset") int offset, @Param("limit") int limit);

在 XML 映射文件中编写 SQL 语句时,无需像手动分表那样关注具体分表的选择,只需要按照常规的查询语法编写,Sharding-JDBC 会在底层根据配置的分表规则自动路由到正确的分表上进行查询并实现分页,示例 SQL 如下:

SELECT * FROM device_status 
WHERE device_id = #{deviceId} 
LIMIT #{offset}, #{limit};

在 Service 层调用该方法即可轻松实现单个设备状态的分页查询,Sharding-JDBC 帮助简化了分表相关的很多复杂操作,提高了开发效率。

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

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

相关文章

nginx的下载与安装 mac

1. 下载 方法一&#xff1a;本地下载 链接&#xff1a;https://nginx.org/en/download.html&#xff08;可直接搜官网&#xff09; 下载到本地后&#xff0c;上传到linux的某个文件夹中 方法二&#xff1a;直接linux上下载&#xff08;推荐&#xff09; wget -c http://ngi…

在 Mac 上配置 Charles,抓取 iOS 手机端接口请求

工具官网&#xff1a;https://www.charlesproxy.com/ Charles 激活码 一、简介 Charles 是一款强大的网络抓包工具&#xff0c;支持 HTTP 和 HTTPS 协议&#xff0c;适用于调试手机 App、微信小程序、H5 页面等网络请求。 它能作为代理服务器&#xff0c;转发并记录本机及其他…

较大项目 git(gitee, github) 拉取失败解决方法

问题描述 近期遇到了一个拉取一个比较大项目失败的问题&#xff0c;229M这么大 每次都失败 我在自己的PC上&#xff0c;只有极好的环境才能拉取&#xff0c;笔记本办公热点怎么都不行 解决办法 后面通过https链接 首次会报错&#xff0c;因为我输入错了gitee的username&am…

爬虫中网络知识基础

HTTP&#xff08;HyperText Transfer Protocol&#xff09;和 HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是互联网上用于传输网页内容等数据的两种主要协议&#xff0c;以下是它们的定义和基本工作原理&#xff1a; HTTP 定义 &#xff1a;HTTP 是一种…

安全工具-二进制安全-testssl.sh

1 需求 --openssl <PATH> &#xff1a;use this openssl binary (default: look in $PATH, $RUN_DIR of testssl.sh) --quiet&#xff1a;dont output the banner. By doing this you acknowledge usage terms normally appearing in the banner --severity <severity…

WHAT - 组件库与 Storybook

文章目录 什么是 Storybook&#xff1f;使用场景举例快速上手教程&#xff08;React 为例&#xff09;1. 安装 Storybook2. 创建一个 Story&#xff08;组件故事&#xff09;3. 启动 Storybook 常用功能常见生态扩展示例&#xff1a;用 Args 和 Controls 动态控制 Props推荐资料…

魔音音乐 5.0.2 | 无损下载 同步网易云歌单UI美观

魔音音乐是一款功能丰富的音乐播放软件&#xff0c;提供高保真音质、智能推荐系统和用户友好界面。其丰富的音乐库几乎覆盖了所有类型的音乐&#xff0c;无论是流行歌曲还是小众音乐&#xff0c;都能在这里找到。这款应用非常适合音乐爱好者使用&#xff0c;它不仅让你享受高品…

云原生时代的中国答案:OLARDB、OceanBase与PostgreSQL的共生革命

以下是对阿里自研数据库的全景式技术调查,重点梳理其产品体系、与PostgreSQL的技术关联及发展历程: 一、阿里自研数据库全景图谱 ​​1. 核心自研产品​​ ​​数据库名称​​​​类型​​​​技术定位​​​​与PostgreSQL关系​​​​PolarDB​​云原生分布式数据库存储计…

HTTP 请求方法与状态码

前言&#xff1a;构建可靠前端应用的 HTTP 通信基础 在当今复杂的 Web 应用生态中&#xff0c;前端开发已远超简单的页面构建&#xff0c;转而成为与后端系统紧密交互的复杂体系。作为这一交互的核心机制&#xff0c;HTTP 协议承载着几乎所有的前后端数据交换&#xff0c;其设…

WIFI原因造成ESP8266不断重启的解决办法

一、报错 报错信息如下&#xff1a; 21:37:21.799 -> ets Jan 8 2013,rst cause:2, boot mode:(3,7) 21:37:21.799 -> 21:37:21.799 -> load 0x4010f000, len 3424, room 16 21:37:21.799 -> tail 0 21:37:21.799 -> chksum 0x2e 21:37:21.799 -> loa…

13.5-13.8. 计算机视觉【2】

文章目录 13.5. 多尺度目标检测13.5.1. 多尺度锚框13.5.2. 多尺度检测13.5.3. 小结 13.6. 目标检测数据集13.6.2. 读取数据集13.6.3. 演示 13.7. 单发多框检测&#xff08;SSD&#xff09;13.7.1. 模型13.7.1.1. 类别预测层13.7.1.2. 边界框预测层13.7.1.3. 连结多尺度的预测13…

RSS解析并转换为JSON的API集成指南

RSS解析并转换为JSON的API集成指南 引言 随着互联网的发展&#xff0c;信息的传播和共享变得越来越重要。RSS&#xff08;简易信息聚合&#xff09;作为一种广泛采用的格式&#xff0c;用于发布经常更新的内容&#xff0c;如博客文章、新闻头条或播客等。它允许用户订阅这些内…

java数据类型详解篇

1、8种基本数据类型 数据类型分类字节数内存位数是否最高位为符号位&#xff08;0正数1负数&#xff09;取值范围&#xff08;数值形式&#xff09;取值说明byte整数类型18是-128 ~ 127-2^7 ~ 2^7 - 1 &#xff08;幂形式&#xff09;short整数类型216是-32,768 ~ 32,767-2^15…

vue 浏览器样式警告:“unknown property name“

浏览器样式警告&#xff1a;"unknown property name"&#xff0c;但在部分电脑上的浏览器又是没有问题的。 这个问题因为没有安装sass或者less&#xff0c;却直接使用了他的语法&#xff0c;比如嵌套样式&#xff1a; body {/* 按钮 */.el-button {background: lin…

postgresql DDL脚本

在PostgreSQL中&#xff0c;数据定义语言&#xff08;DDL&#xff09;脚本用于定义、修改或删除数据库的结构。DDL 操作包括创建表、修改表结构、删除表等。以下是几种常见的DDL操作示例以及如何在脚本中实现它们。 1. 创建表 CREATE TABLE employees (employee_id SERIAL PR…

C#语言入门-task3 :C# 语言的面向对象技术

C# 面向对象编程技术概述 C# 是一种现代化的面向对象编程语言&#xff0c;提供了丰富的特性来支持面向对象的编程范式。以下是 C# 中面向对象编程的核心概念和技术&#xff1a; 核心概念 1. 类与对象 类是对象的蓝图&#xff0c;定义了对象的属性和行为。对象是类的实例。 …

感知框2D反投是咋回事?

一、感知框&#xff1a;“2D 框反投” 是咋回事&#xff1f;&#xff08;以自动驾驶识别车辆为例&#xff09; 1. 核心逻辑&#xff1a;从图像特征 “反推” 目标框 简单说&#xff0c;先用算法在 2D 图像里识别特征&#xff08;比如车辆的轮廓、颜色、纹理&#xff09;&#…

五分钟了解@ExcelIgnoreUnannotated注解

ExcelIgnoreUnannotated 是 EasyExcel 框架中的一个注解&#xff0c;用于控制 Excel 导入/导出时对实体类字段的处理方式。它的作用如下&#xff1a; 核心功能 忽略未标注 ExcelProperty 的字段 当添加 ExcelIgnoreUnannotated 到类上时&#xff0c;EasyExcel 会 跳过所有未显…

Windows电脑数据恢复终极指南:从原理到实战

Windows电脑数据恢复终极指南&#xff1a;从原理到实战 数据丢失是每个电脑用户都可能遭遇的噩梦。本文将为您全面解析Windows平台下的数据恢复技术&#xff0c;从基础原理到高级技巧&#xff0c;帮助您在文件误删、格式化、系统崩溃等情况下找回宝贵数据。 一、数据恢复基础…

【网络入侵检测】基于Suricata源码分析应用协议识别实现

【作者主页】只道当时是寻常 【专栏介绍】Suricata入侵检测。专注网络、主机安全&#xff0c;欢迎关注与评论。 1. 概要 &#x1f44b; 本文聚焦Suricata网络安全引擎的协议解析器实现&#xff0c;详细剖析HTTP、SSL/TLS、FTP、SSH、SMTP等协议的解析流程。 2. 源码分析 2.1 H…