어플리케이션에서 DB를 다루기 위해서는 쿼리를 사용해야 하는데 단순한 쿼리 외에도 여러 방법이 있다.
SQL Statements
가장 오래된 방식이면서 근본적인 방식으로 직접 쿼리문을 작성해 이를 DB에 요청하여 결과 값을 받아오는 방식이다.
장점
- 쉽고 직관적이다.
- 애플리케이션에서 작성한 쿼리를 DB에서 직접 사용할 수 있다.
단점
- 의존성이 강하다.
- SQL 인젝션과 같은 문제가 있다.
- DB의 종류에 따라 문법에 차이가 있어서 각각 DB의 문법을 숙지해야한다.
SQL Mapper
DB의 쿼리문을 객체지향 형태의 함수로 맵핑해주며, 함수를 사용하면 SQL문이 작동된다.
장점
- 코드에 쿼리문이 드러나지 않아 깔끔하다.
- 코드와 쿼리를 분리해 비즈니스 로직과 영속성 부분을 분리할 수 있다.
- 직접 쿼리를 사용하지 않아서 보안성이 뛰어나다.
Stored Procedure
미리 준비된 SQL 코드를 데이터베이스에 저장해놓고 이를 함수처럼 호출하는 방식이다.
장점
- 쿼리가 DB에 저장되어 있어 DB의 내용이 외부로 노출될 위험이 적다. = 보안성이 뛰어나다.
- 호출 시 프로시저 명만 사용하기 때문에 네트워크 트래픽이 적다.
- 실행 속도가 매우 빠르다.
단점
Object-Relation Mapping
현재 프로젝트를 시작 할 때 가장 많이 사용되는 방법이다.
객체와 RDBMS의 테이블 구조를 맵핑해준다. 따라서 클래스를 DB의 테이블, 인스턴스를 ROW 처럼 다룰 수 있다.
장점
- DB의 종류에 독립적이다.
- 쿼리를 별도로 작성할 필요가 없다.
- 생산성이 좋다.
단점
- 잘 사용하기 위해선 결국 DB에 대한 지식이 필요하다.
- ORM으로만 로직을 구현하는 것에는 한계가 있으며 결국 쿼리문을 사용해야 하는 부분이 있다.
ORM VS SP
ORM을 사용한다고 해서 저장 프로시저, SQL Mapper, ... 을 사용하지 못하는 건 아니지만 여러 방식을 사용하면 유지보수 측면에서 어려움이 있다.
ORM 장점
- 비즈니스 로직을 DB가 아닌 프로그램 코드에 모으기 때문에, 로직의 파편화가 적어진다.
- DB와의 상호작용 역시 테스트가 필요한데, 저장 프로시저에 비해 테스트 구성이 쉽다.
- Git과 같은 버전 관리 시스템에서 관리가 편하며, 이력 추적이 용이하다.
- DB 종류에 독립적이기 때문에 특정 DB만을 사용해야 할 이유가 적어진다.
- 추상화가 잘 되어 있으며, 개발자가 상대적으로 DB에 대한 지식이 적어도 된다.
- 로직의 재사용성이 증가하고, 유지보수가 쉽다.
- 기존 CI/CD 파이프라인을 사용하여 배포 관리가 가능하다.
SP 장점
- 쿼리가 아닌 프로시저명을 받기 때문에 상대적으로 네트워크 트래픽이 적다.
- DB에서 로직을 직접 실행시키기 때문에 속도가 매우 빠르다.
- 특정 DB에서 제공하는 세밀한 기능들을 직접 사용할 수 있다.
- DB 로직만 수정할 경우, 컴파일이 필요없이 바로 데이터베이스에 업데이트할 수 있다.
- 디버깅이 쉽다.
결론
옛날에는 프로시저 방식의 개발을 많이 수행했고, 아직도 몇몇 분야에서는 사용하고 있다.
하지만 개발 환경에서 협업의 중요성이 날이 갈수록 중요해지고 있어서 협업 환경에 불리한 프로시저 방식은 잘 사용되지 않는 추세다.
DB는 WAS에 비해서 스케일 아웃이 힘들다. 따라서 로직을 DB 자체에 넣을 경우, DB의 부하가 매우 커지게 되며, 병목 현상이 발생하거나 DB가 뻗을 가능성이 커진다.
따라서 SP를 사용하는 것은 현재 일반적으로 추천되지 않는다.
하지만 DB를 잘 튜닝하거나 쿼리를 최적화하여 한 번에 로직을 실행시켜 빠르게 원하는 값을 얻을 수 있다면, ORM을 이용하여 많은 DB 트랜잭션을 만드는 것보다 좋을 수도 있다.
결국은 서비스의 상황에 맞는 요소를 선택하는 것이 좋을 것이다.
참고
로직을 DB에 넣었을 때 DB 부하가 커진다는 것은 무조건 틀리다곤 할 수 없으나 대개의 경우 사실과 다릅니다. BE에서 데이터에 대한 비즈니스 로직까지 처리하기 때문에, SP로 한 번에 처리할 수 있는 작업을, DB에 여러 번 쿼리를 던지게 되죠. 이 때 던지는 각각의 쿼리가 단순한 쿼리이기 때문에 SP 보다 가벼운 작업이라는 인식이 생기는데, 주목해야 하는 것은.. 한 개의 로직을 처리하는데 들어가는 DB의 총 비용입니다. 이건 단순한 쿼리를 여러 번 던지는 쪽이 높습니다.
하지만 SP를 사용해야 하는 진짜 이유는 성능이 아닙니다.
소프트웨어 공학에서 결합도와 응집도가 중요하다는 것은 모두 잘 아실텐데요. 지금의 ORM 생태계는 BE와 DB의 결합도가 너무나 높습니다. 이 때문에 DB 스키마의 변경이 어려운데, BE의 여러 곳에서 참조하고 있기 때문이고.. 무엇 보다 DB 스키마의 변경은 BE의 수정과 배포를 동반해야 하는 한계가 있습니다. 참고로 ORM에서 엔티티만 함께 수정하면 되는 그런 문제를 얘기하는 게 아닙니다. 비즈니스 로직의 큰 변경으로 DB 마이그레이션을 수반하는 큰 변경 작업이 필요할 때인데, ORM을 사용하면 이런 문제를 정공법으로 돌파하지 못합니다.
여기서 SP가 가치를 지닙니다.
BE와 DB의 인터페이스를 SP로 통일하면, DB 스키마 변경 작업에 제약이 없어집니다. 스키마를 수정하고 영향을 받는 SP를 검색해서 변경하고 배포하면 되죠. 이 과정에서 BE는 아무 것도 할 게 없습니다. 스키마가 변경되어도 인터페이스를 담당하는 SP가 호환성 있는 API를 제공하기 때문에 BE에 아무런 영향을 주지 않기 때문입니다.
SP가 가지는 진짜 문제는, SQL로 SP를 작성하는 프레임워크가 없다는 점입니다. 이런 기법을 일부의 DB 개발자만 알고 있는 거죠.
할 말은 많지만 이만 줄이겠습니다.