Import dữ liệu tốc độ cao trong các ứng dụng Ruby on Rails
Các nền tảng ứng dụng thường cung cấp hộp công cụ xử lý dữ liệu riêng tuy nhiên các công cụ này chỉ phù hợp với tệp dữ liệu nhỏ, vậy đối với khối lượng dữ liệu lớn thì chúng ta thì sao?
Khi chưa có nền tảng Ruby on Rails, đối với những người phải nhập đều đặn một khối lượng dữ liệu khổng lồ, có 1 cách đơn giản là sử dụng ActiveRecord. Tuy nhiên ActiveRecord có cơ chế khiến cho việc tạo bản ghi rất chậm nên việc nhập dữ liệu sẽ ngốn rất nhiều thời gian. Những năm gần đây, công cụ Activerecord-import đã trở thành tiêu chuẩn cho việc nhập dữ liệu khối lượng lớn đạt hiệu quả cao. Vậy còn ngần ngại gì nữa, hãy cùng Bizfly Cloud thử sử dụng công cụ Activerecord-import sẽ giúp bạn nhập dữ liệu lên database nhanh chóng và hiệu quả hơn nhé.
Ví dụ đơn giản:
Thử nhập 100,000 books bằng schema sau:
create_table :books do |t|
t.column :name, :string, null: false
t.column :description, :string
end
Đây là một giải pháp đơn giản sử dụng ActiveRecord:
class Book < ActiveRecord::Base
end
Giả sử convert_csv_to_book_attributes là một phương thức convert CSV thành một mảng chứa các thuộc tính của Book model.
convert_csv_to_book_attributes.each do |attrs|
Book.create!(attrs)
end
Đoạn code trên cực kỳ đơn giản nhưng phải mất khoảng 97 giây để thực hiện. Quá lãng phí thời gian.
Lý do vì sao ActiveRecord lại chậm
Mỗi bản ghi được tạo ra bằng ActiveRecord, đồng nghĩa với việc một câu lệnh truy vấn riêng biệt được tạo ra rồi gửi đến cơ sở dữ liệu. Vì vậy, khi nhập 100,000 books thì đồng nghĩa với gửi 100,000 câu lệnh truy vấn khác nhau tới cơ sở dữ liệu. Sau đó, cơ sở dữ liệu sẽ phải thao tác trên 100,000 câu lệnh riêng biệt và đóng/mở, thêm/ cập nhật 100,000 các thao tác khác để xử lý dữ liệu. Điều đó khiến việc nhập dữ liệu rất mất thời gian.
Các gợi ý để tăng tốc dữ liệu
Tăng tốc độ bằng mẫu import có validations
Thay vì dùng create!, thử xây dựng các Book instances trong bộ nhớ và đưa chúng qua Book.import:
books = convert_csv_to_book_attributes.map do |attrs|
Book.new(attrs)
end
Book.import books
Thao tác chỉ tốn cỡ 5 giây, nhanh hơn 19 lần.
Như vậy, phương thức nhập sẽ tiếp tục có hiệu lực và tìm ra cách tuần tự hóa tất cả các Book Instances thành các câu lệnh SQL có hiệu suất cao.
Tăng tốc độ bằng mẫu import không có validations
Đôi khi trong lúc chuẩn bị dữ liệu khối lượng lớn, chúng ta cần sắp xếp chúng trước, nếu có thể tin tưởng dữ liệu có hiệu lực dựa vào xuất xứ của nó thì ta không cần chạy Activerecord có hiệu lực để nhập dữ liệu.
Để tăng hiệu suất, chúng ta có thể tắt validations trong quá trình nhập:
books = convert_csv_to_book_attributes.map do |attrs|
Book.new(attrs)
end
Book.import books, validate: false
Cách này chỉ mất 4.6 giây để nhập 100,000 books, tốc độ tăng lên gấp 21 lần.
Ở đây ta cài đặt validate: false để thể hiện rằng việc nhập Books có bỏ qua validations. Lựa chọn có giá trị cũng được xác nhận là công nhận là chính xác để thực hiện validations, nhưng bạn cũng có thể giữ validations nếu muốn.
Tăng tốc độ bằng import các cột và giá trị có validations
Đôi khi chúng ta đã có sẵn dữ liệu theo một loạt các giá trị và tất cả những gì chúng ta cần làm là khớp với các cột cần import. Nếu bạn muốn bỏ qua việc tự xây dựng in-memory Book Instances, bạn có thể tự mình chuyển một loạt các cột trong bộ nhớ và các giá trị để đưua vào trình nhập:
# Ví dụ [ ['Book #1', 'Good book'], ['Book #2', 'Great Book'], ...]
array_of_book_attrs = convert_csv_to_book_attributes
Book.import columns, array_of_book_attrs, validate: true
Cách này mất khoảng 7.5 giây, tốc độ đã được cải thiện rất nhiều so với thời gian ban đầu tuy nhiên còn chậm hơn cách dùng mẫu import.
Tăng tốc độ bằng import các cột và giá trị không có validations
Khi chúng ta không cần xây dựng in-memory Book Instances hoặc khởi tạo validations, ta có thể thực hiện việc tăng tốc bằng cách dưới đây:
columns = [:title, :description]
# E.g. [ ['Book #1', 'Good book'], ['Book #2', 'Great Book'], ...]
array_of_book_attrs = convert_csv_to_book_attributes
Book.import columns, array_of_book_attrs, validate: false
Với cách này bạn chỉ mất 2.5 giây. Đây là biện pháp tối ưu nhất trong các mục nêu trên, nhanh hơn tới tận 38 lần.
Benchmarking
Trên đây là các gợi ý để cải thiện tốc độ import dữ liệu khối lượng lớn bằng Activerecord-import. Hãy sử dụng schema trên và xem việc import dữ liệu trên các cơ sở dữ liệu MySQL (InnoDB), PostgreSQL, và SQLite3 hiệu quả như thế nào nhé.
Để chứng minh, chúng tôi sử dụng schema sau đây:
create_table :books do |t|
t.column :name, :string, null: false
t.column :description, :string
end
Kết quả ActiveRecord 4.2.4 trên MySQL (giây)
# of records | ActiveRecord #create | import(models) w/validations | import(models) w/o validations | import(cols, vals) w/validations | import(cols, vals) w/o validations |
10 | 0.017 | 0.001 | 0.001 | 0.002 | 0.001 |
100 | 0.119 | 0.006 | 0.006 | 0.009 | 0.004 |
1,000 | 0.94 | 0.05 | 0.043 | 0.08 | 0.025 |
10,000 | 9.703 | 0.582 | 0.433 | 0.81 | 0.248 |
100,000 | 97.426 | 4.965 | 4.662 | 7.491 | 2.47 |
Kết quả ActiveRecord 4.2.4 trên PostgreSQL (giây)
# of records | ActiveRecord #create | import(models) w/validations | import(models) w/o validations | import(cols, vals) w/validations | import(cols, vals) w/o validations |
10 | 0.034 | 0.002 | 0.001 | 0.002 | 0.001 |
100 | 0.108 | 0.014 | 0.009 | 0.009 | 0.003 |
1,000 | 1.075 | 0.066 | 0.064 | 0.074 | 0.031 |
10,000 | 10.503 | 0.728 | 0.594 | 0.764 | 0.273 |
100,000 | 104.788 | 7.324 | 6.829 | 7.449 | 2.841 |
Kết quả ActiveRecord 4.2.4 trên SQLite3 (giây)
# of records | ActiveRecord #create | import(models) w/validations | import(models) w/o validations | import(cols, vals) w/validations | import(cols, vals) w/o validations |
10 | 0.022 | 0.002 | 0.002 | 0.002 | 0.001 |
100 | 0.168 | 0.009 | 0.007 | 0.01 | 0.003 |
1,000 | 1.613 | 0.069 | 0.057 | 0.079 | 0.027 |
10,000 | 16.894 | 0.764 | 0.594 | 0.783 | 0.28 |
100,000 | 164.348 | 7.45 | 6.621 | 7.531 | 2.562 |
Kết luận
Việc tăng tốc độ import dữ liệu nhanh hơn từ 13 đến 40 lần đã trở nên đơn giản hơn rất nhiều với chỉ một vài dòng code ngắn gọn của Activerecord-import. Hãy thử làm quen với Activerecord-import và biến nó thành cánh tay đắc lực hỗ trợ bạn trong công việc.
Theo Bizfly Cloud chia sẻ
>> Có thể bạn quan tâm: Thu thập địa chỉ Email bằng script ruby bằng mã Jigsaw. Jigsaw