Ruby on Rails中的数据迁移

img



TL; DR请将您的数据迁移代码移至Rake任务或使用成熟的架构样式的gem。通过测试覆盖此逻辑。



我在FunBox担任后端开发人员。对于许多项目,我们正在编写Ruby On Rails后端。我们努力建立适当的开发流程,因此,当遇到问题时,我们会尝试理解问题并提出方法建议。数据迁移问题也发生了这种情况。一次,我在一个单独的包含测试的Rake任务中进行了数据迁移,然后团队提出了一个问题:“为什么不进行模式迁移?” 我在内部聊天中询问开发人员,令我惊讶的是,意见分歧很大。显然,这个问题是模棱两可的,值得深思熟虑的分析和一篇文章。当有人在代码审查中引用此文本的链接,以回答为什么要进行特定数据迁移或相反不进行模式迁移时,为我完成了每篇文章的最大目标计划。



抒情离题



我自己写这篇文章来减轻痛苦并提高团队生产力。一开始,我希望找到确凿的证据来证明将模式迁移误用于数据迁移的危险。与此同时,我正在阅读Nikolai Berdyaev的著作《创造力的意义》。为一个人辩护的经验。”从中我得到了“大教堂精神的概念



IT . Ruby, - . , , . , : , , , , , , .



, , . , , , , .





— , (views), , . .

— (, , , .) . . , . CI, , ( ) SQL , .

— . , DML- UPDATE SQL. . .

(Continuous Delivery) — , .



Rails , , DDL-. , . , Rails omakase- . , .





, , . , . , , . .





. , . (, ) , .





, . . -, , .



deadlocks .



, , , Zero Downtime Migrations Strong Migrations.







— DSL (Domain Specific Language) Ruby DDL- SQL . DSL, , . , .



DSL, , SRP. . , , …



( , )



Ruby On Rails Data Migration , . , . Rails-, . .





SQL ORM ActiveRecord.



:



  1. . .
  2. , .
  3. callbacks , .


«» . , .



«» Rails ( 4.2):



    # db/migrate/20100513121110_add_flag_to_product.rb

    class AddFlagToProduct < ActiveRecord::Migration
      class Product < ActiveRecord::Base
      end

      def change
        add_column :products, :flag, :boolean
        Product.reset_column_information
        Product.all.each do |product|
          product.update_attributes!(:flag => false)
        end
      end
    end


.



, each find_each c batch-.



, , 4.2 .



SQL



, , SQL, :



  1. , . , , , (SQL), .
  2. JOIN-, , .
  3. , deadlock.




Thoughtbot : -, DDL. CI. .



. , , - . , , . , .



, , . , .



, . , .



, , . , , , .



,



, .



, nullable- .



, .



, :



    UPDATE table SET field = 'f' WHERE field IS NULL


:



    class ClientDemandsMakeApprovedNullable < ActiveRecord::Migration
      def up
        change_column_null :client_demands, :approved, true
        change_column_default :client_demands, :approved, nil
      end

      def down
        execute("UPDATE client_demands SET approved = 'f' WHERE approved IS NULL")
        change_column_null :client_demands, :approved, false
        change_column_default :client_demands, :approved, false
      end
    end


, . , , . Dan Mayer Managing DB Schema & Data Changes Modifying Large Tables.







. «», . . , , , .



, .



, , .





, . . REPL .

, :



  1. ;
  2. ;
  3. .


. , . . .

, , , , .



Rake-



, — Rake-. . -.



Rake- . , . . . — .



, , Rake, Thoughtbot:



    # lib/tasks/temporary/users.rake
    namespace :users do
      desc "Actualize achievements counter cache"
      task actualize_achievements_counter_cache: :environment do
        # C (ActiveRelation)   
        users = User.with_achievements
        #    
        puts "Going to update #{users.count} users"
        # ,   ,  
        #    .    
        ActiveRecord::Base.transaction do
          # Batch-   find_each
          users.find_each do |user|        
            #     
            user.actualize_achievements_counter_cache!
            #  
            print "."
          end
        end

        puts "Done!"
      end
    end


each find_each, . memory bloats. Akshay Mohite.



. , Rake- .



, . . , , . .





Mark Qualie up, . «» . :



    class AddLastSmiledAtColumnToUsers < ActiveRecord::Migration[5.1]
      def change
        add_column :users, :last_smiled_at, :datetime
        add_index :users, :last_smiled_at
      end

      class Data
        def up
          User.all.find_in_batches(batch_size: 250).each do |group|
            ActiveRecord::Base.transaction do
              group.each do |user|
                user.last_smiled_at = user.smiles.last.created_at
                user.save if user.changed?
              end
            end
          end
        end
      end
    end


:



    Dir.glob("#{Rails.root}/db/migrate/*.rb").each { |file| require file }
    AddLastSmiledAtColumnToUsers::Data.new.up


Job, .





, - , .



, , .



, . , .



data-migrate (> 670), , Readme. Rails 5+.



, Rails 4+:





. .



, Rake-. . , .



db/data, db/migrate c :



rails g data_migration add_this_to_that


:



rake data:migrate
rake db:migrate:with_data
rake db:rollback:with_data
rake db:migrate:status:with_data


, .





  Rails Rake
+ - - - -
Zero Downtime Deployment - + + + +
Test First - - + +
+ - - +
+ - + + +
+ - - + +


.

— , :



  1. — ;
  2. Zero Downtime Deployment — , ;
  3. Test First — ;
  4. — ;
  5. — , ;
  6. — , , .




, Rake- — .



, . .



, — , . , .







UPD 2020-08-06: Extrapolator « ».

- , Test First .

.



UPD 2020-08-07: . , . . , .



UPD 2020-08-08: , . , . , , . « », , . . , .




All Articles