MySQL & golang gorm 按月份自动分表存储物联网设备日志

更新日期: 2025-03-19 阅读次数: 157 字数: 816 分类: golang

遇到一个存储大量在线设备日志的需求。设备日志通过 MQTT 上传,服务端使用 golang 订阅 MQTT 主题来获取日志,然后存储到 MySQL。之前,为了偷懒,使用了 InfluxDB 2 来存储这里时序数据,但是,经历了一个项目之后,我觉得还是 MySQL 好用。毕竟 influxdb 2.0 的查询语法很不习惯,而且我没有运维经验,这玩意要花时间去了解如何运维,这些时间花费的非常不值。能用最顺手的技术实现,而且稳定可靠,那么就不要折腾。

按照我的估算,按月存储日志,可以把每个表都日志量控制在 1000 万条以内,那么就不需要按天或按周存储了。

今天能把这个功能搞定,就很不错了。也算是设备日志存储上的一大突破。

实现步骤

  1. 让 DeepSeek 描述一下 “golang gorm 按月份存储日志” 的解决方案。我发现给出的方案,应该是完全可行的。
  2. 先让 Github Copilot 实现一版。看看效果。也非常靠谱,claude 3.7 基于现有项目代码的实现,更加完善。只有一点小问题,也很容易修复。
  3. go cron 计划任务自动创建未来几个月的 MySQL 数据表。能兼容表已存在的情况
  4. Ant Design Pro 前端增加月份,日期选择功能。方便切换不同的月份的数据表。

CREATE TABLE IF NOT EXISTS log_202503 LIKE log

每天都能跟着 ai 学习很多新奇又强大的 sql 语句 😅

type Log struct {
    ID            uint
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

// TableName returns the table name for the current log
// Format will be log_YYYYMM, e.g., log_202401
func (Log) TableName() string {
	// Use the current time to determine the table name
	return GetLogTableName(time.Now())
}

// GetLogTableName returns the log table name for a specific time
func GetLogTableName(t time.Time) string {
	return fmt.Sprintf("log_%d%02d", t.Year(), t.Month())
}

// EnsureLogTableExists makes sure the table for the specified time exists
func EnsureLogTableExists(t time.Time) error {
    tableName := GetLogTableName(t)
    // Check if table exists
    var count int64
    DB.Raw("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?", tableName).Count(&count)
    if count == 0 {
        // Table doesn't exist, create it by cloning structure from base log table
        err := DB.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s LIKE log", tableName)).Error
        if err != nil {
            return err
        }
    }
    return nil
}

// EnsureCurrentMonthTableExists makes sure the table for the current month exists
func EnsureCurrentMonthTableExists() error {
    return EnsureLogTableExists(time.Now())
}

这个 SQL 我还是第一次见。

CREATE TABLE IF NOT EXISTS %s LIKE log

挺不错,因为我第一个版本是用的不带分表的 log 表,这样写也挺好的,很方便的基于原有的表结构新创建了表。

插入数据

// 保存 log 到数据库, 需要在当前月份的 log 表中
DB.Table(GetLogTableName(time.Now())).Create(log)

前端

至于前端,就比较简单了,增加了一个年月选择组件,发送到后台过滤即可。

😮‍💨 累坏了

搞定了自动分表,和 mqtt 远程锁机,前后端都搞定,还调研了 emqx 在线设备信息查询。今天超额完成了工作。✌️ 我也放松一下了,累瘫,脑子已经不动了,🥱

📖 继续阅读

EMQX 接口查询 MQTT 设备在线状态

微信关注我哦 👍

大象工具微信公众号

我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式