我有以下情况:
我有一个CLI应用程序,它运行几个未授权的进程,其中大多数是复杂的ETL。
这些情况下的正常工作流程是:
-
将S3 Bucket中的几个文件下载到本地PostgreSQL数据库中,进行一些计算
-
处理、计算并将所有信息聚合到结果数据集中
-
将结果上载到远程数据库
我像往常一样使用标签定义我的模型:
type SalesInfo struct {
FieldA string `gorm:"index"`
FieldB string `gorm:"index"`
FieldC string `gorm:"index"`
FieldD float64
...
FieldZ float64
}
func (SalesInfo) TableName() string {
return "salesinfo"
}
然后我使用迁移器创建结构(事实上,我在每次运行时都会重新创建结构):
// creates the Sales structures
func createStructures() error {
log.Printf("Creating database structures\n")
// LocalDB is a *gorm.DB defined elsewhere
// Ctx is a context.Context defined elsewhere
// table drops
if err := LocalDB.WithContext(Ctx).Migrator().DropTable(&SalesInfo{}); err != nil {
return err
}
// table creations
if err := LocalDB.WithContext(Ctx)AutoMigrate(&SalesInfo{}); err != nil {
return err
}
log.Printf("All structures created\n")
return nil
}
结果是一个空表,其中创建了相应的索引。
当我达到数亿张唱片时,问题就开始了,表现真的很糟糕。手动处理的通常方法是创建没有索引的表,转储数据,然后创建索引。
我现在使用的解决方案是:避免模型上的索引,并在插入后手动创建索引:
型号:
type SalesInfo struct {
FieldA string /*`gorm:"index"`*/
FieldB string /*`gorm:"index"`*/
FieldC string /*`gorm:"index"`*/
FieldD float64
...
FieldZ float64
}
func (SalesInfo) TableName() string {
return "salesinfo"
}
手动索引:
// creates indexes for dumped data
func indexData() error {
log.Printf("Indexing Dumped Data\n")
log.Printf("Indexing FieldA...\n")
if err := LocalDB.WithContext(Ctx).Exec(`Create index i_fielda on "salesinfo"("FieldA")`).Error; err != nil {
return err
}
log.Printf("Indexing FieldB...\n")
if err := LocalDB.WithContext(Ctx).Exec(`Create index i_fieldb on "salesinfo"("FieldB")`).Error; err != nil {
return err
}
log.Printf("Indexing FieldC...\n")
if err := LocalDB.WithContext(Ctx).Exec(`Create index i_fieldc on "salesinfo"("FieldC")`).Error; err != nil {
return err
}
return nil
}
我不喜欢这样,因为:
-
该模型不能代表最终结构
-
我需要为每个索引字段手动编码
-
每次模型更改时,我都需要检查和修改模型外的代码
因此,我尝试了一种“延迟”的索引创建方法或一种没有索引创建方法的表,但找不到使用GORM的方法
我试过了:
if err := LocalDB.WithContext(Ctx).Migrator().CreateTable(&SalesInfo{}); err != nil {
return err
}
要稍后使用类似的内容:
if err := LocalDB.WithContext(Ctx).Migrator().CreateIndex(&SaesInfo{},"FieldA"); err != nil {
return err
}
但是该表是在索引位于第一位的情况下创建的
所以我的问题是:
-
有没有任何方法可以使用gorm在没有索引的情况下创建表?
-
有没有办法在一个命令中创建结构上定义的所有索引?