데이터 인사이트

데이터 전문가 칼럼
데이터 전문가가 전하는 데이터 노하우

보기 좋은 떡이 먹기도 좋다 - 좋은 쿼리 좋은 성능

작성자
관리자
작성일
2020-08-28 18:02
조회
192

이병국의 개발자를 위한 DB 이야기: 쿼리(37회)


보기 좋은 떡이 먹기도 좋다 - 좋은 쿼리 좋은 성능

 

성공과 실패의 경험을 나누자, 용기와 희망을 나누자

개발업무를 시작으로 IT계에 입문했던 필자가 10년 가까이 DB 엔지니어로서 활동하면서 얻은 경험과 지식을 나누고자 한다. DB를 자주 접하는 SW 개발자뿐 아니라, DB 전문가를 꿈꾸는 대학생에서 DB 분야에 입문한 지 1~2년 된 기 입문자가 쉽게 이해할 수 있도록 비유를 통해 쉽게 접근해볼 계획이다. 물론 전문가들이라도 다시 한번 개념을 정립하는 데 필요한 내용이 될 수 있다.

전체적으로 DB의 기본 원리와 개념을 이해하고 테이블, 인덱스, 쿼리, 튜닝, 플랜 등 개발자들이 알아야 하는 DB 전 분야에 대해 쉽게 이해하도록 설명하겠다. DB 기술서적이나 번역서보다는 조금 더 부드럽게 접근할 계획이다. 그렇다고 흔히 서점에서 만날 수 있는 개발자 위주의 SQL 소개서도 아니다. 이 연재는 시리즈로 나갈 것이다. 연재를 끝까지 읽는 독자라면 준전문가 수준의 DB 원리를 이해하는 것을 목표로 한다.
 

보기 좋은 떡이 먹기도 좋다는 말이 있다. 사람들은 미각만으로 맛의 좋고 나쁨을 결정 하지는 않는다. 시각과 후각으로도 맛을 느낀다. 보기 좋게 꾸민 것이 맛있어 보이고, 맛있는 냄새가 식욕을 돋군다.

이번 연재는 좋은 쿼리에 관한 내용이다. ‘보기 좋은 떡이 먹기도 좋다’는 말처럼 좋은 쿼리가 좋은 성능을 낸다. SQL 구문에서 문법적 오류가 없고, 정확한 결과가 나온다고 좋은 쿼리가 되는 것은 아니다. 그렇다면 어떤 쿼리가 좋은 쿼리일까?

 

• 무질서와 질서

무질서한 도로를 달리는 차가 빠른 속도를 내기는 어렵다. 서로 먼저 가려고 교통 법규를 무시한다면 모두가 느려지게 되기 때문이다. 반면 교통 법규를 준수하면서 운전하는 도로를 달리면, 상대적으로 빨리 달릴 수 있다. 약속된 규칙을 준수한다면, 나만 빨리 가지는 못하더라도 모두가 빨리 갈 수 있는 최선의 결과를 얻을 수 있다. 질서를 지켜야만 하는 이유는 그것이 올바른 일이기 때문이 아니라, 최선의 안전과 효율을 제공하기 때문이다. 이와 같은 이유로 SQL 작성 시에도 정해진 규칙에 따라 쿼리를 작성해야 좋은 쿼리가 되고 좋은 성능도 보장한다.


[그림 1] 쿼리 작성규칙 없이 제작된 쿼리

 

만약 대규모 프로젝트에서 [그림 1]과 같이 수백 명의 개발자가 어떠한 규칙도 없이 각자 SQL 구문을 작성한다면 수백 개의 쿼리 패턴이 나타날 것이다. 프로젝트가 끝나고 모든 개발자가 떠난 후에는 수십 명의 운영자가 인수인계를 받아서 운영을 하게 되는데, 이때 많은 문제가 나타나게 된다. 운영자들은 수백 개의 쿼리 패턴과 맞닥뜨리게 될 것이고 그 패턴에 익숙해져야만 제대로 된 운영이 가능할 것이다. 만약 수많은 쿼리 패턴에 익숙해지지 않은 상태에서는 문제 발생 시 빠른 대응을 할 수 없다.

하지만 아래 [그림 2]와 같이 정해진 규칙에 따라 쿼리를 작성한다면 아무리 많은 개발자가 쿼리 작성을 하더라도 동일한 패턴의 쿼리들만 나올 것이다. 이후 소수의 운영 인력만으로도 충분히 유지보수할 수 있다.


[그림 2] 쿼리 작성규칙에 따라 제작한 쿼리

 

필자가 경험한 바로는 여러 개발자가 작성한 각각의 쿼리 패턴도 달랐지만, 개발자 한 명이 작성한 쿼리의 패턴도 다른 경우를 많이 보았다. 쿼리 패턴의 다름은 정해진 규칙 없이 SQL문이 작성된다는 뜻이다. 정해진 규칙에 따라 쿼리를 작성하는 것이 좋은 쿼리이고 좋은 성능을 보장한다고 했다. 이는 약속된 규칙에 따라 작성된 쿼리는 불필요한 오해와 혼란을 최소화하고, 그에 따른 비용을 줄여준다. 여기서 비용은 인건비에 대한 부분을 의미한다.

• 쿼리 작성 규칙

SQL 구문은 문법적 오류가 없고 정확한 결과가 나온다고 해서 선의의 쿼리라 할 수는 없다. 아래 SQL 구문을 살펴보자.

SELECT * FROM 고객정보
Select * From 고객정보
select * from 고객정보
select * from 고객정보

위의 SQL 구문은 문법적 오류가 없으며 동일한 결과를 얻을 수 있다. 하지만 개발자의 성향에 따라서 이와 같이 서로 다른 방식으로 표현한다면 이는 비용 증가로 이어질 수 있다. 왜냐하면 사람은 동일한 쿼리로 인식하지만, 오라클 옵티마이저는 서로 다른 쿼리로 인식하기 때문이다. 이 비용은 오라클 옵티마이저의 분석 비용을 의미한다. 즉 인적 비용이 아닌 물적 비용에 대한 부분이다.

SQL 문은 일반적인 프로그래밍 언어와 달리 처리 절차에 대한 내용은 기술하지 않는다. 단지 원하는 처리 결과만을 표시할 뿐이다. 어떤 인덱스를 사용하고, 어떤 조인을 할 것인가에 대한 결정은 전적으로 오라클 옵티마이저의 분석에 의존한다. 오라클 옵티마이저는 동일한 SQL 문이 연이어 호출되면 분석 작업을 생략한다. 이는 비용 절감을 의미한다. 우리는 SQL 구문을 작성할 때 사람뿐만 아니라 오라클 옵티마이저도 동일한 쿼리로 인식하게끔 작성해야 할 필요가 있다. 즉 동일한 쿼리가 서로 다른 쿼리로 인식되지 않도록 주의해야 한다. 따라서 SQL 구문을 작성할 때 대문자로 할 건지, 소문자로 할 건지, 공백은 어떻게 띄울 건지, 라인은 어느 경우에 바꿀지 등 여러 규칙을 사전에 정의할 필요가 있다. 추가적으로 아래 SQL 구문을 살펴보자.

SELECT * FROM 고객 WHERE 고객번호 = 1234
SELECT * FROM 고객 WHERE 고객번호 = 5678

오라클 옵티마이저는 위 SQL 구문을 서로 다른 쿼리로 인식한다. 하지만 아래와 같이 바인드 변수를 사용하면 동일한 쿼리로 인식한다.

SELECT * FROM 고객 WHERE 고객번호 = :CUST_NO

 

• 하드 파싱과 소프트 파싱

사람은 SQL 구문의 내용을 보면서 쿼리의 동일성 여부를 판단하지만, 오라클 옵티마이저는 SQL 구문을 아스키 값으로 계산해 동일성 여부를 판단한다. 따라서 같은 결과를 얻더라도 대소문자, 띄어쓰기, 줄넘기기, 주석 등의 표현 방식이 조금이라도 다르다면 다른 SQL 문으로 인식한다.

만약 다른 쿼리로 인식한다면 SQL 문을 실행할 때마다 Library Cache에서 하드 파싱을 하게 된다. 빈번한 하드 파싱은 많은 자원을 소모하게 되므로 가능한 한 SQL을 재사용하는 소프트 파싱을 하도록 유도해야 한다. 조건 값 대신에 바인드 변수를 사용하는 것이 대표적인 소프트 파싱의 한 방법이다. 옵티마이저는 바인드 변수에 어떠한 값이 들어와도 동일한 SQL 구문으로 인식하여 소프트 파싱을 하게 된다. 하드 파싱과 소프트 파싱의 구분은 Library Cache에서 SQL 존재 여부로 결정된다.

이번 연재에서는 SQL 구문에서 문법적 오류가 없고, 정확한 결과가 나온다고 해서 좋은 쿼리가 되는 것이 아니라 SQL 작성 시에 정해진 규칙에 따라서 쿼리를 제작하는 것이 좋은 쿼리이고 좋은 성능을 보장한다고 말했다. 또한 하드 파싱과 소프트 파싱에 대해 소개하면서 가능한 빈번한 하드 파싱을 피하고 소프트 파싱으로 유도해야 한다고 했다. 이것이 인적·물적 비용을 줄이는 방법이라고 다시 한번 강조하고 싶다. 표준화한 작성 규칙을 실천하고 가능한 한 하드 파싱을 소프트 파싱으로 유도한다면 유지보수 비용 절감 및 서버 성능 향상을 이룰 수 있다.

다음 회에는 테이블의 수직 및 수평 분할에 따른 성능 향상에 관한 내용으로 찾아 뵙겠다. (다음 회에 계속)

 

 

출처 : 한국데이터진흥원

제공 : 데이터 전문가 지식포털 데이터온에어(dataonair.or.kr)