增加 timescaledb 处理逻辑和gin索引
This commit is contained in:
@@ -118,5 +118,31 @@ func (ps *PostgresStorage) Migrate(models ...interface{}) error {
|
|||||||
return fmt.Errorf("数据库表结构迁移失败: %w", err)
|
return fmt.Errorf("数据库表结构迁移失败: %w", err)
|
||||||
}
|
}
|
||||||
ps.logger.Info("数据库表结构迁移完成")
|
ps.logger.Info("数据库表结构迁移完成")
|
||||||
|
|
||||||
|
// -- 处理gorm做不到的初始化逻辑 --
|
||||||
|
// 创建GIN索引(用于优化JSONB查询)
|
||||||
|
ps.logger.Info("正在为 sensor_data 表的 data 字段创建 GIN 索引")
|
||||||
|
// 使用 IF NOT EXISTS 保证幂等性
|
||||||
|
// 如果索引已存在,此命令不会报错
|
||||||
|
ginIndexSQL := "CREATE INDEX IF NOT EXISTS idx_sensor_data_data_gin ON sensor_data USING GIN (data);"
|
||||||
|
if err := ps.db.Exec(ginIndexSQL).Error; err != nil {
|
||||||
|
ps.logger.Errorw("为 sensor_data 的 data 字段创建 GIN 索引失败", "error", err)
|
||||||
|
return fmt.Errorf("为 sensor_data 的 data 字段创建 GIN 索引失败: %w", err)
|
||||||
|
}
|
||||||
|
ps.logger.Info("成功为 sensor_data 的 data 字段创建 GIN 索引 (或已存在)")
|
||||||
|
|
||||||
|
// 如果是 TimescaleDB, 则将 sensor_data 转换为 hypertable
|
||||||
|
if ps.isTimescaleDB {
|
||||||
|
ps.logger.Info("检测到 TimescaleDB, 准备转换 sensor_data 为超表")
|
||||||
|
// 使用 if_not_exists => TRUE 保证幂等性
|
||||||
|
// 如果 sensor_data 已经是超表,此命令不会报错
|
||||||
|
// 'time' 是 SensorData 模型中定义的时间列
|
||||||
|
sql := "SELECT create_hypertable('sensor_data', 'time', if_not_exists => TRUE);"
|
||||||
|
if err := ps.db.Exec(sql).Error; err != nil {
|
||||||
|
ps.logger.Errorw("将 sensor_data 转换为超表失败", "error", err)
|
||||||
|
return fmt.Errorf("将 sensor_data 转换为超表失败: %w", err)
|
||||||
|
}
|
||||||
|
ps.logger.Info("成功将 sensor_data 转换为超表 (或已转换)")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,19 +10,19 @@ import (
|
|||||||
type SensorData struct {
|
type SensorData struct {
|
||||||
// Time 是数据记录的时间戳,作为复合主键的一部分。
|
// Time 是数据记录的时间戳,作为复合主键的一部分。
|
||||||
// GORM 会将其映射到 'time' TIMESTAMPTZ 列。
|
// GORM 会将其映射到 'time' TIMESTAMPTZ 列。
|
||||||
Time time.Time `gorm:"primaryKey"`
|
Time time.Time `gorm:"primaryKey" json:"time"`
|
||||||
|
|
||||||
// DeviceID 是传感器的唯一标识符,作为复合主键的另一部分。
|
// DeviceID 是传感器的唯一标识符,作为复合主键的另一部分。
|
||||||
// GORM 会将其映射到 'device_id' VARCHAR(50) 列。
|
// GORM 会将其映射到 'device_id' VARCHAR(50) 列。
|
||||||
DeviceID string `gorm:"primaryKey;size:50"`
|
DeviceID uint `gorm:"primaryKey" json:"device_id"`
|
||||||
|
|
||||||
// RegionalControllerID 是上报此数据的区域主控的ID。
|
// RegionalControllerID 是上报此数据的区域主控的ID。
|
||||||
// 我们为其添加了数据库索引以优化按区域查询的性能。
|
// 我们为其添加了数据库索引以优化按区域查询的性能。
|
||||||
RegionalControllerID string `gorm:"size:50;index"`
|
RegionalControllerID uint `json:"regional_controller_id"`
|
||||||
|
|
||||||
// Data 存储一个或多个传感器读数,格式为 JSON。
|
// Data 存储一个或多个传感器读数,格式为 JSON。
|
||||||
// GORM 会使用 'jsonb' 类型来创建此列。
|
// GORM 会使用 'jsonb' 类型来创建此列。
|
||||||
Data datatypes.JSON `gorm:"type:jsonb"`
|
Data datatypes.JSON `gorm:"type:jsonb" json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (SensorData) TableName() string {
|
func (SensorData) TableName() string {
|
||||||
|
|||||||
Reference in New Issue
Block a user