전문가칼럼

DBMS, DB 구축 절차, 빅데이터 기술 칼럼, 사례연구 및 세미나 자료를 소개합니다.

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

전문가칼럼
DBMS별 분류
DB일반
작성자
dataonair
작성일
2017-06-13 00:00
조회
8707




◎ 연재기사 ◎


물탱크 구조로 알아본 오라클의 블록 옵션 ‘PCTFREE와 PCTUSED’


이산가족 찾기 생방송을 통해 배우는 DB 원리


개발자에게 맞는 DB 공부방법 찾기: 물리적 분류와 논리적 분류 그리고 인덱스


데이터베이스 인덱스의 오해와 진실


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (상)


쉬운 것이 올바른 것이다. ‘인덱스 끝장리뷰’ (하)


누구도 알려주지 않았던 ‘오라클 인덱스 생성도’의 비밀


누구도 알려주지 않았던 ‘오라클 쿼리 작성의 비법’


퀴리 최적화 및 튜닝을 위한 오라클 공정쿼리 작성법


만능 쿼리와 한 방 쿼리


오라클 옵티마이저 ‘CBO와 RBO’ 이해하기


재미있는 DB 이야기 ‘60갑자와 쿼리’


그림으로 배우는 ‘오라클 조인의 방식’ 이야기


반드시 알아야 하는 오라클 힌트절 7가지


오라클 플랜을 보는 법


개발자들의 영원한 숙제 ‘NULL 이야기’


알면 유용한 오라클 기능 ‘GATHER_PLAN_STATISTICS’


알면 유용한 오라클 기능들


오라클 DICTIONARY를 활용한 DB툴 프로그램 ‘FreeSQL’


이제는 말할 수 있다: 주식 자동매매 프로그램(상)


이제는 말할 수 있다: 주식 자동매매 프로그램(하)


개발자들이 자주 접하는 오라클 에러 메세지


재미있는 DB 이야기 ‘사라진 날짜를 찾아라’


오라클 랜덤 함수와 사용자 정의 함수


그림으로 배우는 ‘공정쿼리와 인덱스 생성도’


이병국의 개발자를 위한 DB 이야기: 디폴트 세팅의 함정과 오라클 파라미터


재미있는 DB 이야기 ‘놀라운 마방진의 세계’


오라클 운반 최소 단위 BLOCK


이병국의 개발자를 위한 DB 이야기: 이세돌과 알파고의 세기의 대결


이병국의 개발자를 위한 DB 이야기(30회) : DB 엔지니어의 가볍게 읽는 세상 이야기


이병국의 개발자를 위한 DB 이야기: 튜닝(31회) : 개발자를 위한 DB 튜닝 실전(1편)


이병국의 개발자를 위한 DB 이야기: 튜닝(32회) : 개발자를 위한 튜닝 실전(2편)


이병국의 개발자를 위한 DB 이야기: 튜닝(33회) : 개발자를 위한 튜닝 실전(3편)


이병국의 개발자를 위한 DB 이야기: 튜닝(34회) : 개발자를 위한 DB 튜닝 실전(4편)


이병국의 개발자를 위한 DB 이야기: 튜닝(35회) : 개발자를 위한 튜닝 실전(5편)


이병국의 개발자를 위한 DB 이야기: 페이징 처리에 대한 이해 (36회)


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


테이블의 수직분할과 수평분할에 대한 이해


DB 성능 제고를 위한 채번의 이해와 방식별 장단점 비교


이병국의 개발자를 위한 DB 이야기: 마지막회 : ‘개발자를 위한 DB 이야기’ 연재를 마치며



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

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



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

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

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



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

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



무질서와 질서

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

column_img_2899.jpg

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

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

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

column_img_2900.jpg

[그림 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 작성 시에 정해진 규칙에 따라서 쿼리를 제작하는 것이 좋은 쿼리이고 좋은 성능을 보장한다고 말했다. 또한 하드 파싱과 소프트 파싱에 대해 소개하면서 가능한 빈번한 하드 파싱을 피하고 소프트 파싱으로 유도해야 한다고 했다. 이것이 인적·물적 비용을 줄이는 방법이라고 다시 한번 강조하고 싶다. 표준화한 작성 규칙을 실천하고 가능한 한 하드 파싱을 소프트 파싱으로 유도한다면 유지보수 비용 절감 및 서버 성능 향상을 이룰 수 있다.

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