발단
프로젝트 중 핸드폰에 저장된 주소록을 서버로 전송하여 차단된 유저를 확인하고 동작을 구분해야 했다.
차단된 번호는 카운트, 차단되지 않은 번호는 db에 저장하도록 해야 하는데, 사람마다 차단하게 될 번호의 갯수는 제각각이다.
연락처가 100개도 안될 수도 있지만, 10000개가 넘는다던지 하는 경우에 어디까지 저장되었고, 어디부터 다시 저장해야 하는가 하는 그런 동작이 필요했다.
구현 중에 문득 조회하는 시간복잡도에 대한 고민이 생겼다. 배열을 그대로 돌리면 중복값에 대한 불필요한 검사가 반복되기 때문이다. 그래서 이전에 공부했던 Set에 대해 다시 공부하면서 처리한 과정을 써보려 한다.
해결과정
const startSet = performance.now(); // Set 자료구조를 사용한 검색 시간 측정 시작
const uniquePhoneNumbers = Array.from(new Set(dto.phoneNumbers));
for (const phoneNumber of uniquePhoneNumbers) {
if (
blockedListData.find((item) => item.blocked_phone === phoneNumber) ===
undefined
) {
// Set에서 해당 요소를 찾지 못한 경우의 동작
console.log(`${phoneNumber}는 차단되지 않은 번호입니다.`);
} else {
console.log(`${phoneNumber}는 이미 차단된 번호입니다.`);
}
}
const endSet = performance.now();
const setTime = endSet - startSet;
console.log(`Set 자료구조를 사용한 검색 시간: ${setTime}ms`);
const startArray = performance.now(); // 배열을 사용한 검색 시간 측정 시작
for (const phoneNumber of dto.phoneNumbers) {
if (
blockedListData.find((item) => item.blocked_phone === phoneNumber) ===
undefined
) {
// 배열에서 해당 요소를 찾지 못한 경우의 동작
console.log(`${phoneNumber}는 차단되지 않은 번호입니다.`);
} else {
console.log(`${phoneNumber}는 이미 차단된 번호입니다.`);
}
}
const endArray = performance.now();
const arrayTime = endArray - startArray;
console.log(`배열을 사용한 검색 시간: ${arrayTime}ms`);
내가 공부한 내용으로는 Set은 중복 요소를 허용하지 않기 때문에 단순히 dto의 배열 인덱스를 전부 조회하는 것 보다는 Set이 빠를 것 같다고 생각했고, 과연 얼마나 성능의 차이가 있을지 비교가 필요했다.
여기서 비교할 때 주의할 점은 시간을 측정할 때 Array에서 Set으로, 다시 Array로 변경하는 작업을 넣어줘야 정확하게 비교할 수 있다. 이를 빼게 되면 중복된 값을 다 제거하고의 동작을 확인하는 것이니 이미 결과는 정해져 있기 때문이다.
플로우는 다음과 같다.
들어온 배열을 for of 로 조회
vs
들어온 배열을 Set으로 변환, 다시 배열로 변환하여 for of로 조회
약 20개의 번호를 넣고 조회했을 때
Set 자료구조를 사용한 검색 시간: 0.10029196739196777ms
배열을 사용한 검색 시간: 0.41208386421203613ms
정도로 약 4배정도 차이를 확인했다.
약 100개의 번호를 넣고 조회했을 때
Set 자료구조를 사용한 검색 시간: 0.12400007247924805ms
배열을 사용한 검색 시간: 1.2696669101715088ms
정도로 10배정도의 차이를 확인했다.
중요한 것은 Set으로 변환하는 과정을 포함했는데도 애초에 변환하는건 거의 시간에 기별도 안가는 것 같고, 이미 중복된 값을 제한 상태로 조회를 하니 당연히 값이 많아질 수록 Set이 유리했다. 또한 지금은 간단하게 console.log()만 작동시켜서 이정도의 차이를 확인할 수 있는데, 실제 데이터베이스에 값을 넣는 로직으로 변경하게 되면 차이는 훨씬 더 커질 것이다.
코멘트
사실 테스트하는 중간에 Set이 당연히 더 빠를 것이라는 무지성 선입견을 갖고 배열을 변환해서 테스트하는데.. 배열이 더 빠른 결과가 나와서 당황하기도 했다. 왜 Set이 더 빨라야 하는데 배열이 더 빠른지 찾다가 알고보니 내 실수임을 알았다.
클라이언트에서 보내주는 dto의 값을 변환하지 않고 이미 unique로 차단된 번호의 리스트를 굳이 변환하고, 또 반복문은 변환하지 않고 배열로 돌리는.. 변환해야 할건 변환하지 않고 이미 Unique인걸 변환하고 돌리니 당연히 변환하는 과정이 추가된 결과가 더 느릴 수밖에 없지!
무언갈 이해하고 쓰는 것도 중요하고, 그리고 그 과정에서 이해한 그대로 적용하는게 참 중요하다!!!!
'개발 > 프로젝트' 카테고리의 다른 글
[prisma] 서비스 레이어를 거치지 않고 aop개념으로 로직 구현하기 (2) | 2024.10.09 |
---|---|
[aws alb | jenkins] 오토스케일링으로 인해 변경된 Private IP로의 접속 (0) | 2024.06.04 |
에러처리 리팩토링 / 에러핸들링 예시 (0) | 2023.10.25 |
에러처리의 중요성, ... POST, GET의 차이 (0) | 2023.10.24 |
소통의 중요성... feat. JSdoc (0) | 2023.10.16 |