ORM 복잡할시 대처법, 나누어 떨어지는 숫자 배열

김민준·2023년 9월 26일
0

프로그래머스
ORM 사용시 쿼리가 복잡해지면 어떻게 할 것인가?

공부하며 느낀 점
참조한 페이지

프로그래머스

나누어 떨어지는 숫자 배열

우선 나눠지는 원소부터 넣어보고, 예외처리와 정렬을 해보자.

예외처리는 깔끔하니 이제 정렬만하면 될것같다.

나의 풀이

function solution(arr, divisor) {
    var answer = [];
    const length = arr.length

    for (let i = 0 ; i < length ; i++){
        if ( arr[i]%divisor === 0){
            answer.push(arr[i])
        }
    }

    if (answer.length === 0){
        return [-1]
    }

    answer.sort((a,b)=> a-b)
    return answer;
}

다른 사람의 풀이

// 다른 사람의 풀이 1
function solution(arr, divisor) {
    var answer = arr.filter(v => v%divisor == 0);
    return answer.length == 0 ? [-1] : answer.sort((a,b) => a-b);
}

var answer = arr.filter(v => v%divisor == 0);
반복문이 아니라 filter로 딱 나눠지는 요소들만 걸러냈다.

return answer.length == 0 ? [-1] : answer.sort((a,b) => a-b);
이후 길이가 0이면 [-1]을 리턴, 아니면 오름차순 정렬한다.

// 다른 사람의 풀이 2
function solution(arr, divisor) {
    var answer = [];
    arr.map((o) => {
        o % divisor === 0 && answer.push(o);
    })
    return answer.length ? answer.sort((a, b) => a - b) : [-1];

}

비슷하지만 필터대신 맵을 사용하였다.

// 다름 사람의 풀이 3

function solution(arr, divisor) {
    var _ = arr.filter(e => !(e%divisor));
    return _[0] ? _.sort(($,_)=>$-_): [-1];
}

처음거랑 같은데 좀 보기 힘들게 만들어놨다...

속도 비교

아래의 조건으로 1천만회 반복을 하였다.

async function runSolutionWithTiming(solutionFn, arr, divisor) {
  const startTime = new Date();
  for (let i = 0; i < 10000000; i++) {
    await solutionFn(arr);
  }
  const endTime = new Date();
  const executionTime = endTime - startTime;

  console.log(`${solutionFn.name} 실행 시간: ${executionTime}ms`);
}

async function main() {
  const arr = [53, 29, 11, 76, 87, 5, 42, 64, 98, 34];
  const divisor = 6;

  await runSolutionWithTiming(solution0, arr, divisor);
  await runSolutionWithTiming(solution1, arr, divisor);
  await runSolutionWithTiming(solution2, arr, divisor);
  await runSolutionWithTiming(solution3, arr, divisor);
}

main()
  .then(() => {
    console.log("모든 실행이 완료되었습니다.");
  })
  .catch((error) => {
    console.error("에러 발생:", error);
  });

솔루션 3의 경우 조건 !(e%divisor) 이 너무 복잡해서 오래 걸리는것같다.

ORM 사용시 쿼리가 복잡해지면 어떻게 할 것인가?

우선 ORM을 사용하는 이유가 뭘까?
답은 쌩 쿼리를 쓰는것보다 훨씬 간단하기 때문이다. 하지만 그로 인해 속도를 잃게 된다. 왜냐하면 자바스크립트로 오브젝트를 만들고 DB와 매핑을 하기 때문이다. = 추상화

그리고 하나의 테이블이 아니라 여러 테이블을 조인하기 시작하면 ORM 구문이 로우 쿼리보다 더 복잡해 질 수 있다.
하지만 로우 쿼리로도 복잡하기 때문에 쿼리 빌더를 사용하는 것이 좋다고 한다.

그럼 ORM과 쿼리 빌더가 다른 점은 무엇인가?

  • ORM - 객체와 DB를 서로 매핑한다.
  • 쿼리 빌더 - 네이티브 클래스 및 함수를 사용한다.

쿼리 빌더를 사용할 경우의 이득

  1. 사용자의 SQL 쿼리를 이용하여 관리자를 공격하는 것을 막을 수 있다.
  2. 하위 언어의 오타를 감지할 수 있다.
  3. 쿼리를 확장/재사용하기 쉽다.

ORM을 사용할 경우의 이득

  1. 작성이 간단하다.
  2. DB의 상태 변화에 도움이 된다.

요약

  • 복잡하고 정교 : 로우 쿼리
  • 동적이거나 파리미터화 : 쿼리 빌더
  • 특정 DB 시스템 특화 : 쿼리 언어(JPQL 등)
  • SQL에 직접 엑세스하거나 생성 : 쿼리 프레임워크(Query DSL 등)
  • 정적이고 객체 지향언어 : ORM으로 DB의 테이블이 아닌 객체와 작업한다.

공부하며 느낀 점

1. 작동시간을 예측하는 것은 쉽지않다.
오늘 푼 프로그래머스 문제에서 나는 아래와 같이 속도를 예측했다.

내가 푼 방식 > 1,3 번 방식 > 2 번 방식

왜냐하면 1과 3은 표현이 조금 다를 뿐이지 같은 조건이고, 2번 방식은 map을 사용했다. 그러므로, 중간단계가 추가되었고, 그로 인해 더 느려질 것이라는 판단을 했기 때문이다.

실제로는 아래와 같았다.

내가 푼 방식 > 1,2 번 방식 > 3 번 방식

아마 map을 사용하나 filter를 사용하나 실제 속도 차이는 없고, 같은 조건처럼 보여도 부정연산자 !가 하나 붙는 것이 생각 이상으로 큰 차이를 만들어 낸 것같다.

2. ORM이 무조건 좋은가? 에 대해 의문이 들었다.
본인도 프로젝트를 하다가 ORM으로 너무 복잡해서 팀원이 raw query를 사용하는 방식을 제안하였고 그것으로 더 좋은 결과를 냈었다. 단일 table이 아니라 여러 table을 참조해야하는 경우에는 raw query가 활실히 더 좋은 듯하며, query builder의 경우 써본적이 없기 때문에 아직은 이론적으로 밖에 모르겠다. 사용할 기회가 있다면 꼭 사용해봐야겠다.

참조한 페이지

ORM이냐 날쿼리냐 그것이 문제로다
[파이썬][Django] 복잡한 쿼리 작성 방법과 예제
[Django] 장고 ORM vs raw 비교하기
왜 Nodejs ORM을 쓰지 말아야 할까
Raw SQL vs Query Builder vs ORM

profile
node 개발자

0개의 댓글

관련 채용 정보