- 5장 - 반복문2024년 09월 23일
- 31514
- 작성자
- 2024.09.23.:19
반복문 의존증
SQL은 반복문을 만들지 못한 것이 아니라, 필요하지 않아서 만들지 않은 것이다.
호스트 언어(Python, JAVA 등)에서 하나의 레코드마다 작은 SQL을 사용해 접근하는 건 반복계 코드라고 한다.
반복계 코드의 가장 좋은 점은 SQL을 잘 모르더라도 사용할 수 있다는 것이다.
하지만 같은 기능을 구현한다고 가정하면, 반복계로 구현한 코드는 포장계로 구현한 코드에 성능적으로 이길 수 없다.
반복계의 공포 3가지
SQL을 실행할 때는 다음과 같은 과정을 거친다.
- SQL 구문을 네트워크로 전송
- 데이터베이스 연결
- SQL 구문 파스
- SQL 구문의 실행 계획 생성 또는 평가
- 결과 집합을 네트워크로 전송
1번과 5번은 SQL을 실행하는 애플리케이션과 데이터베이스가 물리적으로 같은 위치에 있다면 발생하지 않을 것이다.
2번은 애플리케이션에서 미리 연결을 일정 수 확보해서 오버헤드를 감소시키는 커넥션 풀이라는 기술을 사용하면 거의 문제되지 않는다.
하지만 3번과 4번은 오버헤드가 발생한다.
특히 3번 구문 파스는 DBMS마다 하는 방법도 미묘하게 다르고 종류도 굉장히 많아서 하나의 SQL 구문을 처리할 때마다 비용이 발생한다.
반복계 코드는 병렬 처리하는 최적화가 되지 않는다.
CPU의 멀티 코어로 분산 처리를 할 수 없는 것은 물론 저장소의 분산 효율이 낮다.
DBMS의 버전이 오를수록 옵티마이저는 보다 효율적으로 실행 계획을 세우며, 데이터에 고속으로 접근할 수 있는 아키텍처를 구현한다.
하지만 이러한 노력은 '대규모 데이터 처리'에 포커싱되어 있지, '가벼운 처리'를 빠르게 만드는 것에는 관심이 없다.
따라서 반복계 코드는 미들웨어 또는 하드웨어의 진화에 따른 혜택을 거의 받을 수 없다.
위와 같은 비교가 성립하려면 포장계의 SQL이 충분히 튜닝되어 있다는 전제가 있어야 한다.
무서운 점은 반복계 코드 이러한 튜닝할 수 있는 가능성도 거의 없다.반복계를 빠르게 만드는 방법
- 반복계를 포장계 코드로 변경
- 각각의 SQL 코드를 빠르게 수정
- 애플리케이션 코드에서 다중화 처리
반복계의 장점
실행 계획이 단순하여 변동 위험이 거의 없어서 안정적인 성능과 예상 처리 시간의 정밀도를 확보할 수 있다.
그리고 트랜잭션의 정밀도를 미세하게 제어할 수 있어서 중간에 발생한 오류를 쉽게 처리할 수 있다.
그럼 포장계 코드로 어떻게 반복을 처리할까?
CASE 식과 윈도우 함수를 조합하여 처리할 수 있다.
insert into sales2 select company, year, sale, case sign(sale - max(sale) over (partition by company order by year rows between 1 preceding and 1 preceding)) when 0 then '=' when 1 then '+' when -1 then '-' else null end as var from sales;
SIGN 함수의 리턴값이 0, 1, -1인지에 따라 다른 값을 할당할 수 있다.
위 코드의 실행 계획은 WHERE 구를 사용하지 않았기 때문에 sales 테이블을 풀 스캔하고, 윈도우 함수를 정렬로 실행한다.
만약 위와 같이 반복 횟수가 정해지지 않았다면, 재귀 공통 테이블 식(recursion common table expression)을 사용하거나 중첩 집합 모델을 활용할 수 있다.
-- 재귀 예시 with recursive explosion (name, pcode, new_pcode, depth) as (select name, pcode, new_pcode, 1 from postalhistory where name = 'A' and new_pcode is null union select child.name, child.pcode, child.new_pcode, depth + 1 from explosion as parent, postalhistory as child where parent.pcode = child.new_pcode and parent.name = child.name) select name, pcode, new_pcode from explosion where depth = (select max(depth) from explosion);
반복계와 포장계의 장점과 단점을 고려하고, 어떤 처리 방식을 채택할지를 냉정하게 판단하자
'Book > SQL 레벨업' 카테고리의 다른 글
8장 - SQL의 순서 (0) 2024.09.27 7장 - 서브쿼리 (1) 2024.09.25 6장 - 결합 (0) 2024.09.24 4장 - 집약과 자르기 (0) 2024.09.20 3장 - SQL의 조건 분기 (0) 2024.09.19 다음글이전글이전 글이 없습니다.댓글