5

Tôi đang tạo một bảng mới cần được chèn lấp bằng dữ liệu dựa trên tài khoản Người dùng (trên vài chục nghìn) với tác vụ cào một lần sau đây.Bạn nên chèn lấp một bảng mới trong Rails như thế nào?

Điều tôi quyết định làm là tạo một chuỗi INSERT lớn cho mỗi 2000 người dùng và thực hiện truy vấn đó.

Đây là những gì các mã khoảng trông giống như:

task :backfill_my_new_table => :environment do 
    inserts = [] 
    User.find_each do |user| 
     tuple = # form the tuple based on user and user associations like (1, 'foo', 'bar', NULL) 
     inserts << tuple 
    end 

    # At this point, the inserts array is of size at least 20,000 
    conn = ActiveRecord::Base.connection 
    inserts.each_slice(2000) do |slice| 
     sql = "INSERT INTO my_new_table (ref_id, column_a, column_b, column_c) VALUES #{inserts.join(", ")}" 
     conn.execute(sql) 
    end 
end 

Vì vậy, tôi tự hỏi, là có một cách tốt hơn để làm điều này? Một số hạn chế của phương pháp tôi đã thực hiện là gì? Tôi nên cải thiện nó như thế nào? Điều gì sẽ xảy ra nếu tôi không cắt mảng inserts và chỉ cần thực hiện một đơn INSERT với hơn một vài chục nghìn bộ dữ liệu? Những hạn chế của phương pháp đó là gì?

Cảm ơn!

+0

Tại sao bạn không sử dụng các phương thức MyNewTable được bao bọc trong giao dịch để tăng tốc độ chèn? Ngoài ra, việc triển khai hiện tại sẽ mở bạn đến SQL injection. –

+0

Ồ, tôi nhớ bạn đang thực hiện nhiều lần chèn cùng một lúc. Điều đó thực sự sẽ nhanh hơn (nhưng không chắc chắn bao nhiêu nếu bạn bao bọc chèn bình thường trong một giao dịch nói 1000 mỗi. –

Trả lời

0

Phụ thuộc vào đó PG phiên bản bạn đang sử dụng, nhưng trong hầu hết các trường hợp dữ liệu với số lượng lớn tải vào một bảng điều này là đủ danh sách kiểm tra:

  • cố gắng sử dụng COPY thay vì INSERT bất cứ khi nào có thể;
  • nếu sử dụng nhiều INSERT, vô hiệu hóa tự động và bọc tất cả INSERT trong một giao dịch, tức là BEGIN; INSERT ...; INSERT ...; COMMIT;
  • vô hiệu hóa chỉ mục và kiểm tra/ràng buộc trên/của bảng mục tiêu;
  • tắt trình kích hoạt bảng;
  • alter table để nó trở thành unlogged (kể từ PG 9.5, đừng quên để biến cách đăng nhập vào sau khi nhập dữ liệu), hoặc tăng max_wal_size nên WAL sẽ không bị ngập nước

20k hàng không phải là một việc lớn như vậy cho một PG, do đó, chèn 2k thái lát trong một giao dịch sẽ là tốt, trừ khi có một số rất phức tạp gây nên/kiểm tra liên quan. Nó cũng đáng đọc PG manual section on bulk loading.

UPD: và a little bit old, yet wonderful piece from depesz, trích đoạn:

như vậy, nếu bạn muốn để chèn dữ liệu càng nhanh càng tốt - sử dụng bản sao (hoặc tốt hơn chưa - pgbulkload). nếu vì lý do gì đó bạn không thể sử dụng bản sao, thì hãy sử dụng chèn nhiều hàng (mới trong 8.2!). sau đó nếu bạn có thể, gói chúng trong các giao dịch và sử dụng các giao dịch đã chuẩn bị, nhưng nói chung - chúng không cung cấp cho bạn nhiều.

Các vấn đề liên quan