Insert lượng lớn dữ liệu vào DB sử dụng gem Activerecord-import
Bài đăng này đã không được cập nhật trong 3 năm
Ruby On Rails cung cấp bộ công cụ giúp thao tác với cơ sở dữ liệu một cách dễ dàng, nhưng với những yêu cầu cần insert lượng lớn dữ liệu hàng trăm ngàn bản ghi thì việc insert từng bản ghi sẽ gây mất rất nhiều thời gian. Trong bài viết này giới thiệu giải pháp sử dụng gem "activerecord-import" để tăng tốc insert dữ liệu bằng cách chỉ sử dụng một câu lệnh INSERT.
Bài toán
Nhập 100.000 bản ghi book với thuộc tính như dưới đây
create_table :books do |t|
t.column :name, :string, null: false
t.column :description, :string
end
Dưới đây là một giải pháp sử dụng ActiveRecord
class Book < ActiveRecord::Base
end
100_000.times do |n|
Book.create name: "#book_#{n}", description: "description_#{n}"
end
Tại sao Activerecord lại chậm?
Mỗi khi bạn tạo một bản ghi với ActiveRecord một câu lệnh INSERT được tạo ra và gửi đến cơ sở dữ liệu. Nghĩa là để tạo 100.000 ngàn bản ghi cần tạo 100.000 câu lệnh INSERT, cơ sở dữ liệu phải phân tích cú pháp câu lệnh, mở và đóng kết nối 100.000 lần, điều đó gây tốn rất nhiều thời gian và tài nguyên hệ thống do phải cấp phát hoặc giải phóng bộ nhớ cho 100.000 block.
Vậy cần giải pháp khác hiệu quả hơn.
Gem ActiveRecord import
Cài đặt
Mở Gemfile và chèn vào dòng dưới đây
gem "activerecord-import", ">= 0.2.0"
Tiếp theo thêm vào file application.rb
require "activerecord-import/base"
ActiveRecord::Import.require_adapter('mysql2')
Chạy bundle install
Tăng tốc insert dữ liệu đồng thời validate model
Thay vì sử dụng create!
để thêm từng đối tượng book vào cơ sở dữ liệu, ta tạo một mảng các đối tượng book rồi insert đồng thời cả mảng đó chỉ với môt câu query bằng lệnh Book.import:
books = []
100_000.times do |n|
Book.new name: "#book_#{n}", description: "description_#{n}"
end
# without validations
Book.import books, :validate => false
# with validations
# Book.import books, :validate => true
# when not specified :validate defaults to true
# Book.import books
Theo mặc định giá trị validate bằng true
, phương thức import
sẽ lần lượt validate các model book và build thành một câu query tối ưu.
INSERT INTO books ("name","description")
VALUES ("book_1", "description_1"), ("book_2", "description_2"), ..., ("book_n", "description_n");
Tăng tốc insert dữ liệu bỏ qua validate model
Với những dữ liệu đã được kiểm tra và đẩm bảo thỏa mãn validate, khi import ta có thể thêm tùy chọn validate: false
, điều này cho tốc độ insert cao hơn khi thực hiện với validate.
books = []
100_000.times do |n|
Book.new name: "#book_#{n}", description: "description_#{n}"
end
# without validations
Book.import books, :validate => false
Insert bằng tên columns và giá trị tương ứng ỏ qua tạo model
Thay vì khởi tạo, cấp phát bộ nhớ cho các đối tượng rồi thêm vào mảng, ta có thể tạo một mảng các giá trị tương ứng với từng column name.
columns = [:name, :description]
books = [ ['Book #1', 'Good book'], ['Book #2', 'Great Book'], ...]
Book.import columns, books, validate: true
Bảng đánh giá tốc độ insert
Ta thấy tốc độ khi sử dụng import cao hơn rất nhiều so với create từng record sử dụng ActiveRecord của rails.
Tổng quan
Với những yêu cần cần insert lượng lớn dữ liệu thì giải pháp lần lượt insert từng bản ghi vào cơ sở dữ liệu là không khả thi do tốn nhiều thời gian và tài nguyên hệ thống. Việc sử dụng gem activerecord-import
giúp tối ưu tốc độ và hiệu năng, đồng thời cung cấp các lựa chọn validate
hoặc không 'validate'.
Các bài viết tham khảo
All rights reserved