Sequel을 사용하여 데이터 세트에서 삽입
승인 및 게시 프로세스는 여러 단계로 구성되므로 이러한 이벤트에 대한 로그를 작성하여 PostgreSQL에 저장합니다.우리는 Sequel를 사용하여 데이터베이스 상호작용을 하는데 우리의 로그표는 대체로 다음과 같다.
create_table :activity_logs do
primary_key :id
foreign_key :playlist_id, :playlists, null: false
foreign_key :user_id, :users
String :event, null: false
String :action, null: false
String :message
String :target
Time :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
end
테이블에는 다음과 같은 로깅이 채워져 있습니다.[
...,
{
id: 23,
playlist_id: 103,
user_id: 30,
event: "approval",
action: "approve",
message: "Looks good!",
target: nil,
created_at: Time.utc(2020, 10, 1, 5, 29, 39),
},
{
id: 25,
playlist_id: 423,
user_id: nil,
event: "publication",
action: "published",
message: nil,
target: "Video Wall 1",
created_at: Time.utc(2020, 10, 1, 7, 38, 11),
},
...
]
우리는 결국 모든 열이 두 가지 유형에 적용되는 것은 아니라는 것을 깨달았다.user_id
및 message
열target
및 activity_logs
열 사용.publication_logs
테이블에 저장하는 것이 아니라 발표 로그를 새로운 publication_logs
테이블에 추출하기로 결정했다.1. 새 테이블 만들기
우리는 먼저 필요한
event
표를 만들었다.create_table :publication_logs do
primary_key :id
foreign_key :playlist_id, :playlists, null: false
String :action, null: false
String :target
Time :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
end
activity_logs
, 그리고 user_id
, message
열에서 activity_logs
열을 삭제했습니다. 왜냐하면 이것은 개인이 실행하는 승인 작업에만 적용되기 때문입니다. (발표는 우리 시스템이 자동으로 완성합니다.)다음은 기존 발표 로그를
publication_logs
표에서 새로운 #import
표로 옮기는 것이다.2a.레코드 마이그레이션
데이터를 이전하는 가장 간단한 방법은 모든 기록을 반복해서 반복해서 필요한 형식으로 바꾸고 새 테이블에 삽입한 다음 낡은 테이블에서 데이터를 삭제하는 것이다.
# select records we want to move
publication_logs = from(:activity_logs).where(event: "publication")
# insert each record individually into the new table
publication_logs.each do |log|
from(:publication_logs).insert(
playlist_id: log[:playlist_id],
action: log[:action],
target: log[:target],
created_at: log[:created_at],
)
end
# delete records from the old table
publication_logs.delete
플러그인으로 전환prepared statements하면 다음과 같은 추가 성능 향상을 얻을 수 있습니다.# select records we want to move
publication_logs = from(:activity_logs).where(event: "publication")
prepared_insert = from(:publication_logs).prepare :insert, :insert_publication_data,
playlist_id: :$playlist_id, action: :$action, target: :$target, created_at: :$created_at
# insert each record individually into the new table
publication_logs.each do |log|
prepared_insert.call(
playlist_id: log[:playlist_id],
action: log[:action],
target: log[:target],
created_at: log[:created_at],
)
end
# delete records from the old table
publication_logs.delete
이런 전략은 보통 중소형 테이블에서 양호하게 나타나지만, 공교롭게도 우리는 대량의 기록을 포함하는 로그 테이블 (약 200000개의 IIRC) 이다.장시간 운행하는 이동은 통상적으로 문제가 있기 때문에, 우리는 더욱 좋은 방법을 찾을 수 있다.2b.대량 마이그레이션 기록
대부분의 SQL 데이터베이스는 쿼리에 여러 레코드를 삽입할 수 있으므로 쿼리 속도가 크게 향상됩니다.PostgreSQL에서 구문은 다음과 같습니다.
INSERT INTO my_table (col1, col2, col3, ...)
VALUES ('a1', 'b1', 'c1', ...),
('a2', 'b2', 'c2', ...),
...
Sequel의 경우 INSERT
다중 삽입 기능을 사용하여 열 목록을 첫 번째 매개변수로, 값 배열을 두 번째 매개변수로 사용할 수 있습니다.# select the records we want to move
publication_logs = from(:activity_logs).where(event: "publication")
# insert all new data in a single query
from(:publication_logs).import [:playlist_id, :action, :target, :created_at],
publication_logs.map { |log| log.fetch_values(:playlist_id, :action, :target, :created_at) }
# delete records from the old table
publication_logs.delete
이것은 속도에 있어서 이미 매우 큰 향상이 있었다.그러나 문제는 우리가 데이터를 삽입하기 전에 모든 데이터를 메모리에 불러오는 것이다. 이것은 메모리 사용률을 증가시킬 수 있다.그 밖에 이렇게 많은 기록을 한 번에 삽입하면 데이터베이스에 커다란 부하를 가져올 수 있다.이 두 문제를 해결하기 위해 다중 삽입을 더 작은 횟수로 분해할 수 있습니다.
# select the records we want to move
publication_logs = from(:activity_logs).where(event: "publication")
# bullk-insert new records in batches
publication_logs.each_slice(1000) do |logs|
from(:publication_logs).import [:playlist_id, :action, :target, :created_at],
logs.map { |log| log.fetch_values(:playlist_id, :action, :target, :created_at) }
end
# delete records from the old table
publication_logs.delete
2c.데이터베이스의 레코드 마이그레이션
앞의 방법은 대다수 상황에서 잘 작동할 수 있으나 데이터베이스에서 데이터를 검색하고 약간 수정된 데이터만 보내는 것은 낭비인 것 같다.만약 우리가 데이터베이스 방면에서 이 모든 것을 할 수 있다면, 그것은 매우 좋지 않겠는가?
사실은 우리가 할 수 있다는 것을 증명한다.일반적으로 우리는 원시 값을 전달함으로써
INSERT
문장을 사용한다.단, SELECT
문장도 #import
문장에서 직접 값을 받을 수 있다.INSERT INTO my_table (col1, col2, col3, ...)
SELECT a1, b1, c1, ... FROM other_table WHERE ...
Sequel에서 activity_logs
방법은 데이터 집합의 대상을 받아들여 원시 값을 대체하여 이 기능을 지원합니다.이렇게 하면 마이그레이션을 마지막으로 다시 작성할 수 있습니다.# select the records we want to move
publication_logs = from(:activity_logs).where(event: "publication")
# form a dataset with the new data and insert from that dataset
from(:publication_logs).import [:playlist_id, :action, :target, :created_at],
publication_logs.select(:playlist_id, :action, :target, :created_at)
# delete records from the old table
publication_logs.delete
3. 낡은 기둥 철거
나머지는
activity_logs
테이블에서 발표에 특정한 열을 삭제합니다.alter_table :activity_logs do
drop_column :event # this table will only hold approval logs now
drop_column :target # this was specific to publication logs
set_column_not_null :user_id # only publication logs didn't have user id set
end
성과를 평가하다.
나는 승인 로그 100000개와 발표 로그 100000개로 표를 채우고 우리가 토론한 5가지 이전 정책의 실행 시간과 메모리 분배를 측정했다. (데이터베이스는 PosgreSQL 12)
결과는 다음과 같습니다.
책략
기간
할당된 객체
메모리 할당
개별 삽입
35.7초
61000
478 MB
단독으로 준비한 삽입물
23.8초
48000
634 MB
대량 삽입
8.4초
21k
162MB
대량 대량 삽입
7.9초
21k
158MB
데이터베이스 삽입
2.0초
94
0 MB
예상대로 기록을 단독으로 삽입하는 것이 가장 느린 전략이다.나는 대용량 삽입 정책보다 메모리가 더 많이 분배되는 것을 조금 놀랐지만, 이것은 우리가 모든 기록에 해시를 분배하고, 대용량 삽입은 값 그룹을 분배하기 때문이라고 믿는다.비록 메모리 사용을 늘리는 대가로 준비된 문장이 약 33%의 가속을 제공한 것을 보니 매우 기쁘다.
대량 삽입에 대해, 나는 대량 처리 변체가 더욱 느릴 것이라고 예상한다. 왜냐하면 나는 우리가 감소된 부하를 속도로 바꾸고 있다고 생각하기 때문이다.그러나 나는 그것의 실행 속도가 적어도 비일괄 처리 버전만큼 빠르다는 것에 놀랐다.
데이터로부터 데이터를 집중적으로 삽입하는 효과가 가장 좋다. 왜냐하면 거기에서 데이터베이스가 모든 작업을 완성했기 때문이다.우리의 예에서, 그것은 대량 삽입 정책보다 4배 빠르다.그것은 모든 것이 데이터베이스에서 발생하기 때문에 응용 프로그램 측에 제로 추가 메모리를 분배한다.
script
결어
지난 몇 년 동안, 나는 데이터베이스에서 내가 필요로 하는 대부분의 일을 완성할 수 있는 방법을 찾는 데 점점 흥미를 느꼈다. 특히 내가 Sequel을 사용하기 시작한 이래로.나는 이 속편을 좋아한다. 그것은 나로 하여금 타협하지 않고 내가 하고 싶은 일을 할 수 있게 한다.
우리는 (a) 단독 이전 기록, (b) 대량 이전 기록, 그리고 (c) 데이터 집합에서 이전 기록의 성능을 비교했다.데이터 집중 삽입은 지금까지 가장 빠른 전략으로 코드가 다른 전략보다 복잡하지 않다.
본고는 상당히 간단한 장면을 보여 주었는데, 많은 상황에서 우리의 데이터 이동은 더욱 복잡한 데이터 변환을 필요로 할 수 있다.이런 상황에서 Ruby에서 전환만 하면 유혹적이다. 왜냐하면 우리는 SQL보다 Ruby에 대한 이해가 훨씬 높기 때문이다.그러나 나는 흔히 볼 수 있는 SQL 함수를 배우는 것이 데이터베이스에서 이 일을 완성하는 데 큰 도움이 된다고 생각한다.
Reference
이 문제에 관하여(Sequel을 사용하여 데이터 세트에서 삽입), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/janko/inserting-from-datasets-with-sequel-33an텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)