RDBMS에서 INSERT, UPDATE 쿼리는 성능 문제를 일으키는 경우가 거의 없다. 조회 쿼리는 빈번하게 이루어지기도 하고 어떻게 작성하느냐에 따라 성능차이가 몇백배 차이가 나기 쉽기 때문에 자세히 알아보자.
SELECT, FROM, JOIN, WHERE 등과 같은 키워드를 각 절이라고 한다. 여기서는 각 절의 실행 순서를 알아보자
먼저 대부분의 절이 포함된 경우 실행 순서는 아래와 같다.
WHERE 및 JOIN -> GROUP BY -> DISTINCT -> HAVING -> ORDER BY -> LIMIT
GROUP BY절이 없는 경우 ORDER BY가 WHERE 및 JOIN 다음으로 실행된다. 간혹 원하는 데이터를 조회하기 위해선 실행 순서가 바뀌어야 되는 경우가 있다. 예를 들어 LIMIT 절을 먼저 적용하고 정렬을 적용하고 싶다면 인라인 뷰(FROM절 서브쿼리)를 사용 해야한다.
인덱스를 조건 절의 사용할 경우 값의 변형이나 자료형이 맞지 않으면 인덱스를 사용해서 조회하지 않으니 주의하자.
다중컬럼 인덱스인 경우가 중요한데 WHERE 절의 인덱스에 포함된 컬럼이 여러개일 경우 WHERE 절의 명시된 순서는 중요하지 않다. 옵티마이저가 이를 알아서 해결해 주어 다중 인덱스를 사용한다. 하지만 해당 인덱스에 컬럼이 조건 절의 순서대로 있느냐가 중요하며 동등 비교 조건인지 범위 비교 조건인지가 중요하다.
인덱스 앞쪽 순서에 있는 컬럼이 범위 비교 조건으로 사용된다면 뒤에 컬럼이 조건이 어떤 것이든 사용하지 못하게 된다.
따라서 다중 인덱스인 경우 앞쪽 컬럼을 되도록 동등조건이 사용되는 컬럼으로 설정하자.
OR 연산자를 사용하는 조건1과 조건2가 있을때 조건1이 인덱스를 사용한다 해도 조건2의 해당하는 데이터를 조회할려면 풀 테이블 스캔을 이용해야한다. 따라서 해당 쿼리는 풀 테이블 스캔이 된다. 만약 두 조건 다 인덱스를 사용한다면 풀 테이블 스캔보다는 빠르지만 인덱스를 하나로 이용할때보다 느리니 OR 연산자는 주의해서 사용하자.
아래는 다중 컬럼 인덱스를 기준으로 설명했지만 단일 컬럼 인덱스도 동일하게 적용된다.
ORDER BY 절은 GROUP BY 절의 사용하기 위한 조건에서 하나 더 추가된다. 인덱스에 정렬은 오름차순, 내림차순으로 설정할 수 있는데 다중컬럼 인덱스의 경우 각 컬럼별로 방향을 선택해서 지정할 수 있다.
여기서 중요한 점은 전체 다중 컬럼에 방향을 설정된 방향인 정방향으로 이용하냐 아니면 역방향으로 함께 사용해야한다는 점이다. 앞쪽 컬럼은 정방향, 뒤쪽 컬럼은 역방향으로 정렬해서 조회하면 인덱스를 사용할 수 없게 된다.
보통 조회 쿼리는 WHERE절과 ORDER BY(GROUP BY)절과 같이 사용되는 경우가 많다. 따라서 아래와 같은 순서로 인덱스를 생성하면 효과적으로 쿼리 성능을 올릴 수 있다.
쿼리를 사용할때 아래 질문에 순차적으로 대답 해보며 인덱스를 효율적으로 사용할 수 있는지 판단해보자. 다만 해당 절이 없는 경우 생략할 수 있다.
WHERE| (GROUP BY&ORDER BY) 절이 인덱스를 사용할 수 있는가?- WHERE절이 인덱스를 사용할때
GROUP BY|ORDER BY절이 인덱스를 사용할 수 있는가?- GROUP BY 절과 ORDER BY절이 동시에 인덱스를 사용할 수 있는가?
COUNT() 함수는 레코드 개수를 가져오는 함수이다. 를 많이 사용하는데 는 레코드 자체를 의미한다. 특히 조건절과 같이 사용되는 경우 실제 필드를 읽는 쿼리와 같이 동작하기 때문에 COUNT 쿼리가 성능 문제가 되는 경우가 있다.
따라서 아래와 같은 점 확인하자!
FROM 절에 테이블이 무조건 드라이빙 테이블이 되는것이 아니다. 옵티마이저에 선택에 따라 JOIN 절에 테이블이 드라이빙 테이블로 선택될 수 있다.
조인을 사용할 경우 드라이빙 테이블(조인시 먼저 조회되는 중심 테이블)은 한번만 조회되고 드리븐 테이블은 드라이빙 테이블에 로우 수 만큼 반복 조회된다.
따라서 A,B 라는 테이블이 조인하게 될때 조인하는 컬럼이 인덱스가 아닌 테이블을 드라이빙 테이블로 사용하고 인덱스인 테이블을 드리븐 테이블로 선택될 가능성이 높으며 둘 다 없을 경우는 로우수가 적은 테이블이 드라이빙 테이블로 사용되는게 효율적이다.
JOIN에 사용되는 컬럼은 데이터 타입이 맵핑되는 컬럼과 같아야 효율적으로 조인 될 수 있다. 같지 않을 경우 풀 테이블 스캔을 하여 조인하게 된다.
따라서 데이터 베이스에 표준화된 자료형 타입을 사용하며 자주 조인되는 컬럼은 같은 자료형으로 변경하도록 고민해보자!
이너 조인을 사용할 수 있는 테이블을 아우터 조인을 사용하게 되면 드라이빙 테이블로 선택될 가능성이 없어지기 때문에 해당 테이블에 인덱스를 사용할 수 있는 기회조차 없어지게 된다!
아우터 테이블에 조건절을 본문 Where절에 사용할 경우 이너 조인으로 변경하여 조회된다. 따라서 아래와 같은 내역을 확인하고 사용하자.
아우터 조인이 원래대로 동작하길 원하는 경우인 드라이빙 테이블은 전체 데이터가 나와야하고 아우터 조인되는 데이터에 대해 조건이 필요한 경우 ON 절에 조건절 작성
드라이빙 테이블에서 조회하는 데이터가 아우터 조인되는 테이블 필드의 값의 따라 조회되는 데이터가 다른 쿼리의 경우 본문 Where절에 조건절 작성
조인이 사용된 쿼리를 튜닝하는 방법 중 하나로 조인과 함께 GROUP BY, ORDER BY를 사용하면 조인한 결과에 대해 GROUP BY나 ORDER BY가 이루어진다. 이를 GROUP BY, ORDER BY가 적용된 인라인뷰 형태로 적용하고 생성된 임시 테이블에 조인을 거는 방법을 사용하는 튜닝 방법이다.
조인되는 개수가 줄어 성능이 향상되는 효과도 있지만 정렬이나 그룹핑 처리를 위한 버퍼를 나중에 필요한 만큼만 사용하기 때문에 메모리 사용에도 효율이 증가한다.
조인시 드라이빙 테이블에 인덱스가 있어 드라이빙 테이블 기준으로 정렬된 결과가 반환될거라 생각하지만 옵티마이저 상황(해시조인, 네스티드 루프 조인등)에 따라 정렬 순서가 드라이빙 테이블 인덱스 정렬 순서와 달라 질 수 있다.