DBMS와 실행 계획

유석현(SeokHyun Yu)·2022년 9월 29일
0

SQL

목록 보기
38/45
post-thumbnail

서론

RDB를 조작할 때는 SQL이라는 전용 언어를 사용한다.

사용자 또는 개발자가 데이터베이스에서 의식적으로 사용하는 것은 SQL 레벨까지이다.

이후의 모든 것은 SQL 구문을 읽어들인 DBMS가 알아서 처리하고 결과를 제공해준다.

따라서 사용자는 데이터가 있는 곳을 알 필요도 없고, 데이터에 접근하는 방법도 따로 생각하지 않는다.

이러한 모든 것은 DBMS에게 맡긴다.


1. 권한 이양의 죄악

RDB는 모든 일을 사용자가 아니라 시스템에게 맡겼다.

따라서 사용자가 하는 일은 대상을 기술하는 것으로 축소되었다.

RDB가 이렇게 대담하게 권한 이양을 감행한 데는 당연히 정당한 이유가 있다.

바로 '그렇게 하는 것이 비즈니스 전체의 생산성을 향상시키기 때문'이다.

물론 현재 상황을 놓고 보면 이러한 말은 반은 맞고 반은 틀렸다.

맞다는 것은 RDB가 시스템 세계의 곳곳에 침투해 있는 것을 보면 알 수 있다.

반면 틀렸다는 것은 여전히 우리가 RDB를 다루기 어려워한다는 점을 보면 알 수 있다.

SQL은 초기에 생각했던 것처럼 그렇게 간단한 언어가 아니다.

또한 SQL 구문을 의식하지 않고 사용하는 것 때문에 성능 문제로 고생하는 경우도 꽤 있다.

RDB가 숨기고 있는 내부 절차를 들여다봐야 하는 것은 이러한 이유 떄문이다.


2. 데이터에 접근하는 방법은 어떻게 결정할까?

앞에서 설명했던 것처럼 RDB에서 데이터 접근 절차를 결정하는 모듈을 쿼리 평가 엔진이라고 부른다.

쿼리 평가 엔진은 사용자로부터 입력받은 SQL 구문을 처음 읽어들이는 모듈이기도 하다.

쿼리 평가 모듈은 추가로 파서 또는 옵티마이저와 같은 여러 개의 서브 모듈로 구성된다.

- 파서(parser)

파서의 역할은 이름 그대로 파스(구문 분석)하는 것이다.

사용자로부터 입력받은 SQL 구문이 항상 구문적으로 올바르다는 보증이 없으므로 검사를 해주는 것이다.

사용자가 쉼표 쓰는 것을 잊거나, FROM 구에 존재하지 않는 테이블 이름을 쓰거나 했을 때는 서류 심사에서 미리 떨어뜨리는 것이다.

그렇게 해야 DBMS 내부에서 일어나는 후속 처리가 효율화된다.

사실 구문 분석이라는 것은 SQL에 한정되는 것이 아니라 일반 프로그래밍 언어의 컴파일 시점에서도 실행되는 것이다.


- 옵티마이저(optimizer)

서류 심사를 통과한 쿼리는 옵티마이저로 전송된다.

옵티마이저이 한국어 번역은 '최적화'이다.

이때 최적화의 대상은 데이터 접근법(실행 계획)이다.

옵티마이저가 바로 DBMS 두뇌의 핵심이다.

옵티마이저는 인덱스 유무, 데이터 분산 또는 편향 정도, DBMS 내부 매개변수 등의 조건을 고려해서, 선택 가능한 많은 실행 계획을 작성하고, 이들의 비용을 연산하고, 가장 낮은 비용을 가진 실행 계획을 선택한다.


- 카탈로그 매니저(catalog manager)

옵티마이저가 실행계획을 세울 때 옵티마이저에 중요한 정보를 제공하는 것이 카탈로그 매니저이다.

카탈로그란 DBMS 내부 정보를 모아놓은 테이블로, 테이블 또는 인덱스의 통계 정보가 저장되어 있다.

따라서 이러한 카탈로그 정보를 간단하게 '통계 정보'라고 부르기도 한다.


- 플랜 평가(plan evaluation)

옵티마이저가 SQL 구문에서 여러 개의 실행 계획을 세운 뒤 그것을 받아 최적의 실행 결과를 선택하는 것이 플랜 평가이다.

이후에 실제로 몇 가지 실행 계획을 직접 살펴보겠지만 실행 계획이라는 것은 곧바로 DBMS가 실행할 수 있는 형태의 코드가 아니다.

오히려 인간이 읽기 쉽게 만들어진 문자 그대로의 '계획서'이다.

따라서 성능이 좋지 않은 SQL 구문이 있을 때 실행 계획을 읽고, 수정 방안 등을 고려할 수 있다.

이렇게 해서 하나의 실행 계획을 선택하면, 이후에 DBMS는 실행계획을 절차적인 코드로 변환하고 데이터 접근을 수행한다.


3. 옵티마이저와 통계 정보

이상이 DBMS가 쿼리를 읽어들여 실제로 데이터 접근을 수행할 때까지의 흐름이다.

옵티마이저 내부에서 일어나는 처리는 따로 다루지 않는다.

오히려 데이터베이스 사용자로서는 옵티마이저를 잘 사용하는 것이 더 중요하다.

이렇게 말하는 이유는 옵티마이저가 명령하는 대로 다 잘 처리해주는 만능은 아니기 때문이다.

특히 카탈로그 매니저가 관리하는 통계 정보에 대해서는 데이터베이스 엔지니어가 항상 신경 써줘야 한다.

플랜 선택을 옵티마이저에게 맡기는 경우, 실제로 최적의 플랜이 선택되지 않는 경우가 꽤 많다.

옵티마이저가 실패하는 패턴이 몇 가지 있는데, 통계 정보가 부족한 경우가 대표적인 원인으로 꼽힌다.

구현에 따라 차이는 있지만 카탈로그에 포함되어 있는 통계 정보는 다음과 같은 것들이다.

- 각 테이블의 레코드 수
- 각 테이블의 필드 수와 필드의 크기
- 필드의 카디널리티
- 필드값의 히스토그램(어떤 값이 얼마나 분포되어 있는가)
- 필드 내부에 있는 NULL 수
- 인덱스 정보

이러한 정보를 활용함으로써 옵티마이저는 실행 계획을 만든다.

문제가 생기는 경우는 이러한 카탈로그 정보가 테이블 또는 인덱스의 실제와 일치하지 않을 때이다.

테이블에 데이터 삽입/갱신/제거가 수행될 때 카탈로그 정보가 갱신되지 않는다면, 옵티마이저는 오래된 정보를 바탕으로 실행 계획을 세우게 된다.

옵티마이저는 과거 정보밖에 가지고 있지 않으므로 어쩔 수 없이 잘못된 계획을 세울 수밖에 없다.


4. 최적의 실행 계획이 작성되게 하려면

올바른 통계 정보가 모이는 것은 SQL 성능에 있어서 굉장히 중요한 문제이다.

따라서 테이블이 데이터가 많이 바뀌면 카탈로그의 통계 정보도 함께 갱신해야 한다는 것은 데이터베이스 엔지니어의 상식이다.

수동으로 처리되는 경우도 많고, 정기적으로 통계 정보 갱신 작업이 수행되는 경우도 있으며, 갱신 처리가 수행되는 시점에 자동으로 통계 정보를 갱신하는 DBMS도 있다.

통계 정보 갱신은 대상 테이블 또는 인덱스의 크기와 수에 따라서 몇십 분에서 몇시간이 소요되기도 하는, 실행 비용이 굉장히 높은 작업이다.

하지만 DBMS가 최적의 플랜을 선택하려면 필요한 조건이므로 갱신 시점을 확실하게 검토해야 한다.

profile
Backend Engineer

0개의 댓글