대용량 CSV 파일 처리 시 일반적인 Ruby 개발자들은 다음과 같은 방식으로 데이터를 처리합니다.
ruby
candidates = CSV.read("candidates.csv", headers: true)
comments = CSV.read("candidates_comments.csv", headers: true)
comments.each do |comment|
candidate = candidates.find { |c| c["id"] == comment["candidate_id"] }
# puts candidate["name"]
end
이 방식은 작은 데이터셋에서는 문제가 없지만, 대규모 데이터셋에서는 O(m*n)의 시간 복잡도로 인해 무한 루프에 빠지거나 메모리 부족으로 스크립트가 중단될 수 있습니다. 각 comment마다 candidates 배열 전체를 탐색하기 때문입니다.
이를 개선하기 위한 더 효율적인 접근 방식은 Hash 룩업을 활용하는 것입니다.
ruby
candidates_by_id = {}
candidates.each do |candidate|
candidates_by_id[candidate["id"]] = candidate
end
comments.each do |comment|
candidate = candidates_by_id[comment["candidate_id"]]
# puts candidate["name"]
end
find vs Hash 성능 비교
Hash 룩업 방식은 다음과 같은 이점을 제공합니다.
- 시간 복잡도:
find/select: 매번 배열 전체를 검색하므로 O(m*n)Hash: 키를 통해 직접 접근하므로 O(1) (평균적으로)
-
속도: 벤치마크 결과,
Hash룩업 방식이find방식보다 훨씬 빠릅니다. 제공된 예시에서는find방식이 0.137초 걸린 반면,Hash룩업은 0.0006초로 약 220배 이상 빨랐습니다. - 메모리:
Hash방식은 전체candidates데이터를 메모리에 미리 로드해야 하므로find방식보다 초기 메모리 사용량이 증가할 수 있습니다. 예시에서는find방식이 0.83MB를 사용한 반면,Hash방식은 1.67MB를 사용하여 더 많은 메모리를 사용했습니다.
결론
find와 Hash 접근 방식의 선택은 데이터셋의 크기, 복잡성, 그리고 작업 환경(머신 성능)에 따라 달라집니다. 대용량 데이터와 충분한 머신 자원이 있는 경우, Hash 룩업 방식은 시간을 크게 절약할 수 있는 매우 효과적인 해결책입니다. 데이터가 자주 변경되지 않는 상황에서는 한 번의 초기 매핑으로 반복적인 검색 시간을 단축할 수 있습니다.