이번에 SP를 작성하며 IF-ELSE 구문이 많아 실행 계획이 매번 다르게 선택되다가 어느 순간 제대로 계획을 선택하지 못하게 될거라는 피드백을 받았다.
IF-ELSE 분기가 많으면 입력값마다 완전히 다른 쿼리 경로가 실행된다.
SQL Server는 SP 실행 시 처음 실행된 계획을 캐시하며, 이를 계획 캐싱이라고 한다.
하나의 실행 계획만을 캐시하는데, SP 내부의 분기마다 쿼리 구조가 크게 달라진다면
하나의 경우에 대해서만 최적화된 계획을 생성해 다른 계획에 대해서는 비효율적이거나 잘못된 계획이 쓰일 수 있다.
특히 통계 정보 업데이트가 지연되면, 비효율적인 실행 계획이 재사용돼서 성능이 급격히 나빠지는 SP가 되어버릴 수 있다.
이를 파라미터 스피닝 문제라고도 한다.
그럼 분기처리를 못하나?
CASE문은 IF-ELSE와 달리 하나의 쿼리로 인식되기 때문에 계획 캐시 문제를 거의 일으키지 않으며
옵티마이저가 더 잘 최적화할 수 있다.
옵티마이저는 한번에 컴파일 되는 단위로 실행 계획을 생성하는데,
CASE문은 한번에 컴파일되어 하나의 실행 계획을 만들게되는 반면
IF-ELSE문은 각 조건에 대한 처리가 따로 컴파일되어 여러 실행 계획을 만들게 된다!
그중 하나만이 캐싱되고, 이를 적절하지 못하게 재사용하게 되어 성능 저하가 발생한다는 것!
그럼 CASE문만 쓰면 되겠다?!
둘은 사용에 있어서 큰 차이점이 있다.
IF-ELSE에서는 조건에 따라 다양한 작업을 지정해 수행할 수 있지만
CASE문에서는 간단한 값 선택 및 계산 등의 조건분기만 가능하다는 점이다.
결국 CASE문에 IF-ELSE문을 완전히 대체하기는 어렵다.
하지만 불필요한 IF-ELSE문을 CASE로 바꿈으로써 성능 향상을 노려볼 수는 있겠다.
또 IF-ELSE 사용을 지양해야하는 이유 중에는 원래 절차지향 프로그래밍 언어가 아닌 SQL 쿼리에서 절차형 로직을 과하게 사용하면 결국 RDB의 장점을 살리지 못할 수 있다는 점이 있다.
결론적으로는 성능을 저하시킨다는 말이다.