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

文章目录

    遇到一个存储大量在线设备日志的需求。设备日志通过 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 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式