old style
내가 배웠던 join은 from 절에 join하고자 하는 테이블 명을 모두 쓰고 where 조건으로 검색하는 방식이었다.
SELECT m.no, m.name, m.profileImage,
p.no, p.name, p.price
FROM member m, product p
WHERE m.no = {no}
하지만 프로젝트 진행 시 join하는 테이블의 수가 많아지면서 가독성이 떨어졌다. 여기에 페이징 처리를 위한 TOP n 방식과 동적 쿼리문까지 쓰다보면 내가 쓰지 않은 쿼리를 수정할 때 힘든 것은 물론 내가 쓴 쿼리도 알아보기가 힘들었다.
Good practice of sql
그래서 어떤 방식으로 쿼리를 써야 좋은 것인지 한 번 찾아보았다. 여러 포스팅에 걸쳐 공통적으로 언급된 내용들과, 또 그중 내 수준에서 필요한 부분들만 모아서 정리해보았다.
Avoid using Asterik(*)
테이블에 컬럼 수가 적으면 괜찮을지 모르지만, 컬럼 수가 많을 때 asterik를 쓰면 실제 쿼리에 필요 없는 컬럼까지 색인하게 되므로 쿼리 성능이 떨어질 수 있다. 또 개인적인 경험으로는 내가 만들지 않은 쿼리를 다룰 때 *로만 표기되어 있으면 어느 컬럼을 추출하려는지 확실하지 않아 코드의 목적을 파악하기가 어려울 때가 있었다. 그러면 쿼리를 수정해야 하는지, dto를 손봐야 하는지 헷갈리기도 했다.
따라서 반드시는 아니더라도 필요한 컬럼을 명시해주는 쿼리를 지향해야겠다.
Table alias
from 절에 여러 테이블을 쓸 경우 alias가 선호된다. 가독성이 좋고, 다른 테이블에 같은 컬럼명이 있을 때에도 혼란을 방지한다. 너무 당연한 것이지만 그래도 적어둔다.
ANSI SQL style
예시처럼 내가 배운 join 방식은 from 절에 관련된 모든 테이블을 적고 where 절로 필터링하는 식의 방법이었다. 작성하지 간단하지만 쿼리가 길어질수록 가독성이 떨어진다. 또 불필요한 컬럼까지 모두 색인한 뒤 마지막에 where 절로 필터링하기 때문에, 내가 진행한 작은 규모의 프로젝트에서는 문제가 되지 않지만 데이터가 큰 경우 성능의 차이가 발생할 수 있다.
ANSI sql은 표준 sql으로 모든 DBMS에 공통적으로 사용할 수 있다. 위의 예시를 ANSI style로 수정해보면
SELECT m.no, m.name, m.profileImage,
p.no, p.name, p.price
FROM member m,
JOIN product p
ON m.no = p.no
WHERE m.no = {no}
정도가 된다. JOIN도 종류가 네 가지로 나뉜다.
source: https://www.w3schools.com/sql/sql_join.asp
JOIN만 쓰면 INNER JOIN이다. 내가 배웠던 예전 방식으로 한다면 full outer join을 한 뒤에 where로 필터링만 하는 것으로 이해하면 되겠다.
JOIN과 ON 절을 쓸 때 알아 두어야 할 점은 아래 링크에 설명이 잘 되어있다. 간략히 정리하면 where의 경우 join이 끝난 후에 마지막에 필터링을 하고, on의 경우 join 이전에 하기 필터링을 한다는 점이다.
sql join where vs. on - Stackoverflow
EXISTS, NOT EXISTS than IN, NOT IN
EXISTS, IN 모두 서브쿼리를 활용할 때 사용할 수 있는 구문이다. EXISTS가 훨씬 선호되는데 가장 큰 이유는 EXISTS는 해당 서브쿼리에 해당하는 값이 하나라도 있으면 검색을 멈추지만, IN의 경우는 모든 인덱스를 검색하기 때문에 성능 상의 차이가 난다. 같은 맥락으로 검색하는 경우가 아니고서는 LIKE보다 항등연산자(=)를 사용하는 것이 바람직하다.
sql을 쓸 때에도 협업과 유지보수를 고려하여 가독성 있게 짜는 것이 중요하겠다. 이상으로 오늘은 간단히 좋은 sql을 쓰는 방법 몇 가지를 알아보았다.
references
https://www.dpriver.com/blog/2011/09/27/a-list-of-sql-best-practices/
https://codingsight.com/sql-query-optimization-tips/