쿼리 튜닝(Feat. MS-SQL) - 튜닝의 기본/쿼리 최적화 방법

nana·2024년 4월 13일
2

DataBase

목록 보기
1/8

첫 회사는 쿼리를 짜면 DBA가 튜닝을 해 주고 인덱스 힌트와 옵션까지 다 지정해서 피드백을 주었기 때문에 튜닝에 대한 중요성을 인지하지 못 했고, 개발자는 튜닝은 할 줄 몰라도 된다고 생각했다.
그런데 첫 회사가 특이했던 것 같다...

이직 후 단순 조회를 하면서도 속도이슈로 기능 자체를 사용하지 못 하는 경우가 생기면서 튜닝에 대한 중요성을 몸소 느끼게 되었고 뒤늦게나마 쿼리 공부를 시작하게 되었다.
이제 더이상 쿼리튜닝은 DBA의 전유물이 아닌 개발자들이 갖춰야 할 필수역량이 (오래 전에)되었다고 생각한다.

What is Tuning?

그래서 쿼리 튜닝이 뭔데?

SQL 쿼리를 강화하여 서버의 처리 속도를 올리는 것

정석으로는 실행계획을 보고 과부화 걸린 부분을 해결하면 되지만, 그 전에 기본적인 것들 부터 체크하고 간다면 의외로 문제는 간단하게 풀릴 수도 있다는걸 경험으로 알게되었다.

1. Select * 를 지양한다.

대부분의 개발자들이 select * 를 이용해서 전체 컬럼을 조회한다.
꼭 필요한 컬럼이 아닌 전체 컬럼을 조회하게 되는 경우 부하를 줄 수 있다.
그리고 처음 생성한 테이블은 컬럼이 적어서 전체를 조회 했다고 하더라도 테이블 컬럼이 늘어나서 예상치 못한 곳에서 조회 속도가 느려질 수 있다.

그러니 필요한 데이터만 select문에 작성하도록 하자!
덤으로 가독성도 좋아진다 :)

2. View 테이블 조인은 지양한다.

편하게 사용하려고 view 테이블을 만들었을 것이다.
정말 간단한 조회에서만 사용하고 실제 서비스되는 프로시저에서는 뷰를 사용하지 않는 것이 좋다. 뷰는 너무 많은 컬럼을 반환하며 실제로 뷰에 있는 테이블 조인을 풀어서 작성하는 것 만으로도 성능 개선이 된 경우를 꽤 많이 경험했다.
(다음에 뷰에 관한 것도 한번 적어야겠다)

3. 중복되는 테이블 조인은 임시 테이블로 만든 뒤 활용해 보자.

테이블 여러개를 결과값으로 뱉어내는 프로시저의 경우 조인되는 테이블이 중복되는 경우가 있다.
이 때 중복되는 조인 테이블을 임시 테이블로 먼저 조인 후에 그 임시 테이블을 활용하여 결과A, 결과B를 추출하면 테이블 끼리의 조인에서 딜레이 되는 시간을 현저히 줄일 수 있다.

4. Cross Join이 아닌 Inner Join을 활용하라.

어찌보면 당연한 얘기지만 Inner Join으로 가져 오는 데이터를 최적화 해야한다.
cross join은 Catesian Product라고 하기도 하며 조인되는 두 테이블에서 곱집합을 반환한다. 1000 열이 있는 테이블과 100열이 있는 테이블을 크로스조인 하면 100000 열을 가져오게 된다.
inner join은 키 값이 있는 테이블의 컬럼 값을 비교 후 조건에 맞는 값을 가져오는 것이다. 간단히 말하면 서로 연관된 내용만 검색하는 조인 방법이다. 

5. 와일드카드(%) 사용은 지양하자.

성능으로 따지면 %로 비교하는 것 보다 동등연산자(=)로 비교하는 것이 훨씬 빠르다.
그렇지만 어쩔 수 없이 사용해야 하는 일도 있는 법..
와일드 카드는 되도록 a like '%test' 보다는 a like 'test%' 처럼 절의 끝에서만 사용하자.

6. Union 보다는 Union All을 사용하자.

Union 연산자는 연결된 쿼리에서 동일한 로우는 제거하고 한 로우만 반환하게 된다.
추가적으로 필터링 하는 로직이 숨어 있으므로 Union all보다 비용이 높을 수 밖에 없다.

7. 긍정적인 연산자 사용.

이건 쿼리 기초 강의에서 배운건데
not like보단 like가, <>보단 =가, NOT IN보단 IN이 대체로 좀 더 좋은 성능을 낸다고 한다.

8. DISTINCT는 가급적 사용하지 않는다.

DISTINCT는 중복된 결과값을 제외하기 위해 사용하는데, 모든 쿼리를 그룹핑해서 결과를 내 놓기 때문에 성능을 저하시킬 수 있다.
꼭 필요한 컬럼만 group by 절에 추가하여 그룹핑하도록 하자.

9. 인덱스 컬럼은 변형하여 사용하지 않는다.

인덱스 컬럼은 변형되었을 때 인덱스의 효력을 잃는다.
ex) start_date가 인덱스인 경우

where convert(varchar(10), start_date, 121) = '1900-01-01' 

이런식으로 변형하지 않도록 하자.

10. 필터를 사용할 때 Having보다는 Where절에서 해결하자.

Having은 Where절 보다 연산 순위가 후순위이므로 where절 까지 나온 결과로 having에서 처리한다. 만약 쿼리를 필터하는게 조건에 기반해 있다면, HAVING 보다 WHERE이 더 효율적이다.

==================================================================

튜닝공부는 하면 할 수록 배울게 많은 것 같다.

쿼리 용도마다 다르고 데이터 양, sql종류에 따라 다를 수 있으니 참고정도만 하고 요리조리 조합해서 최적의 결과를 만들어 내시길😘

** 참고 자료

더 빠른 SQL 쿼리를 위한 21가지 데이터베이스 튜닝 규칙
https://www.itworld.co.kr/news/105792
거꾸로 바라본 세상:티스토리
https://clairdelunes.tistory.com/22
SQL 튜닝(일반적인 SQL 튜닝 기법)
https://cornswrold.tistory.com/87

profile
BackEnd Developer, 기록의 힘을 믿습니다.

0개의 댓글