복잡한 쿼리를 피하는 방법

여러분은 다른 사람이 작성한 복잡한 쿼리를 분석하느라 고생한 경험이 있으신가요? 저는 암호라고 해도 될 정도로 복잡한 쿼리를 만나서 매우 당황했던 기억이 있습니다. 하나의 쿼리가 다양한 일을 하고, 심지어 불필요한 작업들을 포함하기도 합니다. 쿼리를 몇 번이고 반복해서 읽으며 정확히 분석하지 않으면 무슨 일을 하는 녀석인지 알 수 없는 것이 복잡한 쿼리의 특징입니다.

이 테이블 저 테이블을 조인하면서 데이터를 마구 가져오며, 조건문, NULL 처리, 각종 함수와 서브 쿼리 등을 조합하여 쉽게 알아볼 수 없도록 휘저어 놓습니다. 비즈니스 로직과 쿼리문이 뒤섞여 있습니다. 심한 경우에는 작성자가 정말 이 쿼리를 정확히 이해하고 작성한 게 맞는지 의심이 되기도 합니다. 특히 팀에 합류한 지 얼마 되지 않아 이런 쿼리를 분석해야 한다면 꽤 애를 먹게 될 겁니다.

쿼리 작성자는 쿼리에 조금씩 살을 붙여가며 최강의 쿼리를 만들어 냅니다. 그리고 코드를 짜다 보면 이 쿼리를 조금 바꿔서 사용하면 좋을 것 같다는 생각을 하게 됩니다. 작성자는 이 쿼리를 해독할 수 있기 때문에 그대로 복사하여 붙여 넣고 원하는 대로 조금 바꿔서 사용합니다. 이런 상황이 반복되어 여기 저기서 복잡한 쿼리를 사용해 코드를 구현해 두었다고 가정해 봅시다. 그리고 우리가 이 팀에 합류하게 되었다고 생각해보는 거예요.

복잡한 쿼리의 문제점 및 개선 방법

우리는 어떤 기능을 구현하는 과정에서 DB와 통신이 필요합니다. 그래서 비슷한 일을 할 것으로 추정되는 기존의 코드를 살펴봅니다. 그러다 문제의 쿼리를 마주쳤다고 생각해 봅시다. 특별한 이유가 없다면 적어도 데이터의 유효성을 검증하거나 데이터에 변경을 가하는 등의 작업은 코드로 표현되어 있는 게 좋지 않았을까요? 그런 작업들이 쿼리 안에 섞여 있다면 여러 곳에서 중복이 발생할 수 밖에 없고, 개발자가 중요한 로직을 누락할 가능성이 높아집니다. 또한, 하나의 쿼리가 너무 많은 일을 하게 되면 이해하기 힘들 뿐 아니라 재사용성도 떨어집니다.

예를 들면, 학생의 휴대폰 번호를 이용해 학생 테이블에서 어떤 학생 A를 찾아서 A의 학번을 이용해 강의 테이블을 조회해서 A가 수강중인 강의 목록을 구하고, 수강중인 강의 목록 중에 영어 알파벳이 있다면 대문자로 변환하는 쿼리가 그런 경우입니다.

이 쿼리는 세 가지 일을 합니다. 첫 번째로 학생 A의 학번을 구합니다. 두 번째로 A의 학번으로 A가 수강중인 강의 목록을 구합니다. 세 번째로 수강중인 강의 목록 중에 영어 알파벳이 포함되면 대문자로 변환합니다.

하나의 복잡한 쿼리를 여러 개로 분리하자

학생 A의 학번을 구하는 쿼리와 학생 A가 수강중인 강의 목록을 구하는 쿼리는 서로 분리하는 게 좋습니다. 개발자가 코드를 작성하다 보면 학생 A의 학번만 구하고 싶을 수도 있고, 어떤 학번의 학생이 수강중인 강의 목록만 구하고 싶을 수도 있기 때문입니다. 필요하다면 두 개의 쿼리를 한 번씩 실행해서 학생 A가 수강중인 강의 목록을 얻을 수 있습니다. 코드의 중복을 줄이고 재사용성을 높이기 위해 메서드를 추출하는 것과 같은 이치입니다.

이 때 주의할 사항은 하나의 쿼리를 여러 개로 분리함으로써 성능에 문제가 발생하지 않는지 고려해야 한다는 것입니다. 문제가 발생한다면 쿼리를 복잡하게 만들어 문제를 해결하려고 하기 보다는 코드를 수정해서 문제를 해결할 생각을 하는 것이 좋습니다.

비즈니스 로직을 섞지 말자

그리고 수강 중인 강의 이름 목록에서 영어 알파벳이 포함된 경우 대문자로 변환하는 로직은 코드로 작성되는 편이 좋습니다. 그러지 않으면 개발자가 비즈니스 로직을 분석할 때 코드만 보는 것이 아니라 쿼리까지 일일이 분석해야 하기 때문입니다. 또한, 강의 이름에 대한 일관성을 지키기 위해 강의 이름을 가져오는 쿼리가 포함될 때마다 소문자를 대문자로 변환 하는 과정을 중복해서 작성해야 하는 문제가 있습니다.

개발자가 쿼리를 주의 깊게 분석하지 않았다면 쿼리에서 소문자를 대문자로 변환한 것이 아니라 DB에 저장된 데이터를 그대로 가져오기만 했다고 생각할 확률이 높습니다. 원래 알파벳이 대문자로 저장되어 있다고 생각하고 개발했다가 나중에 강의 이름에 소문자 알파벳이 포함된 것을 발견하고 코드를 수정해야 하는 일이 발생하게 됩니다. 비즈니스 로직을 쿼리에 섞어서 혼란을 초래하지 않도록 주의합시다.

정답이 정해져 있는 것은 아니지만, 필자는 팀의 생산성을 높이기 위해서 복잡한 쿼리를 작성하지 않고, 비즈니스 로직을 쿼리와 분리하는 것이 원칙이 되어야 한다고 생각합니다. 쿼리의 재사용성이 높아지고, 개발자가 비즈니스 로직을 파악하고 관리하기 쉬워지기 때문입니다.

소프트웨어는 유지 보수 주기가 매우 깁니다. 몇 번 사용하고 버릴 코드가 아니라면 유지 보수성을 고려해야 합니다. 나를 거쳐간 코드를 분석하고 유지 보수 하게 될 다른 개발자들을 배려해야 합니다. 그래서 우리는 언제나 타인이 읽기 좋고 고치기 쉬운 코드를 작성하기 위해 최선을 다해야 합니다.

스스로 경험하며 얻은 깨달음을 공유하기 좋아하며, 세상이 필요로 하는 코드를 작성하기 위해 노력하는 개발자입니다.

“복잡한 쿼리를 피하는 방법”의 2개의 댓글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다