insert_all을 사용하여 Rails에서 많은 레코드 만들기
Address.create(data)
를 실행하는 것이 좋은 생각인가요? 아니, 아마 아닐거야. Rails 데이터베이스에서 데이터를 대량으로 생성하는 더 좋은 방법이 무엇인지 알아보겠습니다.앱
고객 데이터가 포함된 csv 파일에서 데이터를 가져오는 앱을 만들고 있습니다. 파일에는 6개의 필드로 구성된 1,000개의 행이 있습니다. 다음과 같이 보입니다.
id,first_name,last_name,email,gender,ip_address
1,Lianne,Hosten,[email protected],Female,112.33.73.252
2,Aubrie,Dorin,[email protected],Female,254.88.120.47
...
요구 사항은 간단합니다. csv의 각 행에
Customer
라는 저장된 ActiveRecord 대응 항목이 있어야 합니다.모델
모델 및 관련 마이그레이션:
# The model
class Customer < ApplicationRecord
end
# And its migration
class CreateCustomer < ActiveRecord::Migration[7.0]
def change
create_table :uploads do |t|
t.string :first_name
t.string :last_name
t.string :email
t.string :gender
t.string :ip_address
t.timestamps
end
end
end
데이터 삽입
앱에 csv 파일을 도입하는 방법에는 여러 가지가 있습니다. URL에서 다운로드하거나 파일 시스템 또는 파일 입력이 있는 제출된 양식에서 읽을 수 있습니다. 어느 쪽이든 대부분 컨트롤러 작업에서 csv 파일로 끝납니다.
작동시키기
소프트웨어를 개발할 때 대부분의 경우 성능에 집중하기 전에 먼저 작업을 수행하는 데 집중해야 합니다. 따라서 작동하는 것을 만들어 봅시다.
require 'csv'
require 'benchmark'
class CustomersController < ApplicationController
def create_bulk
file = params[:csv_file] # Uploaded through a form
time = Benchmark.measure do
CSV.open(file.path, headers: true).each do |row|
Customer.create(row)
end
end
puts time
end
end
벤치마크 결과:
3.884280 0.871490 4.755770 ( 13.748814)
예, 내 컴퓨터에서 1,000명의 고객을 생성하는 데 13초가 걸렸습니다. 250,000개를 수입한다고 상상해보세요...빠르게 작업하기
너무 느립니다. 우리 뭐 할까?
insert_all
이라는 ActiveRecord의 메서드가 있습니다.메서드
insert_all
는 레코드당 속성 배열을 수신하고 SQLINSERT
문을 생성하여 모든 레코드를 한 여행에 삽입합니다. 예를 들어:customers = [
{first_name: 'Lianne', last_name: 'Hosten', email: '[email protected]', gender: 'Female', ip_address: '112.33.73.252'},
{first_name: 'Aubrie', last_name: 'Dorin', email: '[email protected]', gender: 'Female', ip_address: '254.88.120.47'},
...
]
Customer.insert_all(customers)
결과 SQL 문:
Customer Bulk Insert (7.9ms) INSERT INTO "customers"
("first_name","last_name","email","gender","ip_address","created_at","updated_at")
VALUES
('Lianne', 'Hosten', '[email protected]', 'Female', '112.33.73.252', STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'), STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
('Aubrie', 'Dorin', '[email protected]', 'Female', '254.88.120.47', STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW'), STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')),
...
앱에서 시도해 봅시다.
...
class CustomersController < ApplicationController
def create_bulk
file = params[:csv_file] # Uploaded through a form
time = Benchmark.measure do
CSV.open(file.path, headers: true).each_slice(250) do |rows|
Customer.insert_all(rows.map(&:to_h))
end
end
puts time
end
end
벤치마크 결과:
0.047267 0.035247 0.082514 ( 0.130676)
이봐,
each_slice
가 뭐야? 일반적으로each
는 배열을 열거하고 작업할 각 요소를 제공합니다. 그러나 each_slice
는 작업할 n개의 요소를 다시 제공합니다. 네, 배열을 돌려줍니다.csv에는 1,000개의 행이 포함되어 있으므로 위의 코드는 1,000
INSERT
쿼리 대신 1,000/250 = 4 SQLINSERT
쿼리를 생성합니다. 가져오기 속도를 높이는 또 다른 점은 Customer
모델이 인스턴스화되지 않아 훨씬 더 많은 CPU 주기를 줄일 수 있다는 것입니다.13초가 아닌 0.13초... 100배 빨라졌습니다.
알겠습니다.
#create
를 다시 사용해야 하는 이유는 무엇입니까? 계속 읽어보세요.가능할 때마다 insert_all을 사용해야 합니까?
와우, 100배 빠르다, 캐치가 있어야 한다. 예, 있고 큰 것입니다. 여기서 큰 단점은 콜백과 유효성 검사가 트리거되지 않는다는 것입니다.
반복합니다:
insert_all
를 사용할 때 콜백 및 유효성 검사가 트리거되지 않습니다.따라서
insert_all
와 함께 사용하는 데이터가 유효한지 확인하십시오. 콜백을 확인하여 insert_all
이전 또는 이후에 실행해야 하는 항목이 있는지 확인하십시오.중요 사항
insert_all
는 콜백 및 유효성 검사를 무시해도 되는 경우에만 사용하십시오. Reference
이 문제에 관하여(insert_all을 사용하여 Rails에서 많은 레코드 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/lorankloeze/creating-lots-of-records-in-rails-with-insertall-1bhe텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)