Gem activerecord-import in rails

1.Giới thiệu

ActiveRecord-importlà một thư viện dùng để insert một số lượng lớn các bản ghi vào trong cơ sở dữ liệu sử dụng ActiveRecord.

ActiveRecord-import tương thích với Rails version 3.x trở lên.

2.Tại sao dùng activerecord-import

Bởi vì ActiveRecord không hỗ trợ việc thêm đồng thời nhiều bản ghi cùng một lúc mà phải thêm tuần tự từng bản ghi một , điều này rất tốn thời gian và làm giảm hiệu suất.

3.Bài toán

Giả sử chúng ta có một model locations có quan hệ has_many user_locations .Khi chúng ta muốn insert 100 locations mới với 1k user_locations . Với việc sử dụng ActiveRecord cần 100 câu lệnh SQL để thêm mới 100 locations và 100x1000 câu lệnh SQL để thêm mới 1k user_locations, và điều đó đã làm giảm hiệu suất. Ngược lại , nếu chúng ta sử dụng activerecord-import thì chúng chỉ cần 2 câu lệnh SQL để có thể import chúng một cách dễ dàng và làm giảm hiệu suất đáng kể .

4.Cài đặt và sử dụng

  1. using Gem, bundle
gem "activerecord-import"

2.Thực thi

locations = []
    100.times do |i|
      locations << Location.new(:place_name => "ninh binh #{i}")
    end
    Location.import locations

Ở đoạn code trên, ta khởi tạo 1 mảng locations, sau đó thêm các bản ghi vào mảng locations. Sau đó dùng lệnh Location.import locations để import các bản ghi này vào database.

5.Tính năng

Một trong những tính năng chính của activerecord là tạo ra số lượng câu insert nhỏ nhất , tránh vấn đề N+1 câu insert.

Dưới đây là danh sách các tính năng mà activerecord-import cung cấp :

  • activerecord -import có thể làm việc với model objects(nhanh)
    .import(*args)Object

Imports một tập các giá trị vào cơ sở dữ liệu

Sử dụng hiệu quả hơn khi dùng ActiveRecord::Base#create hoặc ActiveRecord::Base#save, tiết kiệm rẩt nhiều thời gian. Phương pháp này hoạt động rất tốt khi bạn muốn tạo nhiều hơn 1 bản ghi tại thời gian đó và không quan tấm đến ActiveRecord::Callbacks trong quá trình import.

Model.import array_of_models

Với cách này bạn có thể imports một mảng các đối tượng mà bạn muốn cập nhật.

  • activerecord-import có thể làm việc với các cột và mảng các giá trị(nhanh nhất)
Model.import column_names, array_of_values

Tham số đầu tiên column_names là một mảng các symbol hoặc chuỗi quy định các cột mà bạn muốn cập nhật . Tham số thứ 2 array_of_values là một mảng bao gồm các mảng con , mỗi mảng con bao gồm các giá trị của bản ghi mới tương ứng theo trật tự với tên cột mà bạn muốn cập nhật .

  • activerecord-import có thể thực hiện trên các bản cập nhật có sự trùng lặp(chỉ dùng với Mysql) và có thể thực hiện validatetions(nhanh)
Model.import column_names, array_of_values, options

Với cách này 2 tham số đầu tiên tương tự như cách viết trên nhưng với tham số thứ 3 options là 1 hash , chúng có thể là các options dưới đây :

Options

  • validate(true/false):
columns = [ :lat, :long, :place_name ]
values = [ ['-3.261177', '22.851563', 'Ninh Binh'], ['15.527791', '12.656250', 'Gia Lai'] ]

# Importing without model validations
Location.import columns, values, :validate => false

# Import with model validations
Location.import columns, values, :validate => true

# when not specified :validate defaults to true
Location.import columns, values
  • on_duplicate_key_update: Có thể sử dụng một mảng hoặc 1 hash

Sử dụng mảng :

Location.import columns, values, :on_duplicate_key_update=>[ :lat, :long, :place_name ]

Sử dụng hash :

Location.import columns, attributes, :on_duplicate_key_update=>{ place_name: "Ninh Binh" }
  • synchronize : 1 mảng dùng để đồng bộ dữ liệu đã tồn tại trong DB và dữ liệu mới cập nhật.
locations = [ Location.new :place_name=>'Ha Noi',
          Location.new :place_name=>'Ha Noi ',
         Location.new :place_name=>'Ha Noi 3']
location = Location.where(place_name: 'Ha Noi').first

columns = [ :place_name]
values = [ [ 'Ninh Binh' ] ]
Location.import locations, :synchronize=>[ location]
puts location.place_name # => 'Ninh Binh'
  • timestamps(true/false) : true - import dữ liệu thêm timestamps kể cả nó đã có trong ActiveRecord::Base , false : sinh lỗi ActiveRecord::StatementInvalid:

  • recursive(true/false) : Sử dụng khi muốn import một object có quan hệ has_many associations :

    Giả sử có quan hệ Locations has_many User_Locations

 locations = []
10.times do |i|
  location = Location.new :name: "Location #{i}"
  location.user_locations.build user_id: user.id
  locations << location
end
Location.import locations, recursive: true

Khi đó ngoài việc insert được các bản ghi về locations mà đồng thời các bản ghi về user_locations cũng được insert .

  • Trong trường hợp các bản ghi quá lớn ,để tránh trường hợp quá tải chúng ta có thể sử dụng batch_size để điều khiển số lượng bản ghi được import :
 Location.import locations, batch_size: 5

Returns -failed_instances : Một mảng các đối tượng mà validate fails và không được commit vào database