代码之家  ›  专栏  ›  技术社区  ›  Pablo Ponte

GORM Migrator创建不带索引的表

  •  0
  • Pablo Ponte  · 技术社区  · 2 年前

    我有以下情况:

    我有一个CLI应用程序,它运行几个未授权的进程,其中大多数是复杂的ETL。 这些情况下的正常工作流程是:

    1. 将S3 Bucket中的几个文件下载到本地PostgreSQL数据库中,进行一些计算
    2. 处理、计算并将所有信息聚合到结果数据集中
    3. 将结果上载到远程数据库

    我像往常一样使用标签定义我的模型:

    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
    
    }
    

    我不喜欢这样,因为:

    1. 该模型不能代表最终结构
    2. 我需要为每个索引字段手动编码
    3. 每次模型更改时,我都需要检查和修改模型外的代码

    因此,我尝试了一种“延迟”的索引创建方法或一种没有索引创建方法的表,但找不到使用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
        }
    

    但是该表是在索引位于第一位的情况下创建的


    所以我的问题是:

    1. 有没有任何方法可以使用gorm在没有索引的情况下创建表?
    2. 有没有办法在一个命令中创建结构上定义的所有索引?
    0 回复  |  直到 2 年前