쿼리 속도를 올리는 방법은 어떤 게 있을까? - 아키텍처적으로

쿼리의 성능 개선을 최대한으로 뽑았음에도 불구하고, 해당 쿼리의 속도가 기본적으로 느린 경우가 있다.

이런 경우에 대해서는 해당 쿼리가 경로를 크게 탐색하지 않도록 도와주는 것이 중요하다.

아키텍처적인 관점으로 접근해, 해당 쿼리가 빠르게 특정 데이터의 위치를 찾을 수 있도록 도와줄 수 있다.

테이블 구조: 인덱싱

테이블에 지정하는 인덱스는 해당 테이블 내에서 탐색에 대한 힌트를 주는 방법이다.

자주 사용되는 컬럼에 대해서 미리 줄을 세워 두는 것이다.

이렇게 인덱스를 지정해 줌으로써 데이터의 한 줄 서기가 가능해지고, 이 줄은 쿼리가 빠르게 값을 탐색하도록 돕는다.

그러나 잘못 지정되었거나 과도한 인덱싱은 더 많은 읽기/쓰기 부하를 일으키기도 하고, 인덱스를 위한 저장 공간을 추가로 소비하기도 한다.

또한 인덱스의 개수가 너무 많아지는 경우, 옵티마이저가 인덱스를 잘못 선택할 확률이 높아진다. 인덱스의 개수는 3-4개 정도가 가장 적당한 것으로 알려져 있다.

인덱스 손익 분기점을 고려해, Full Scan보다 느린 인덱스 액세스는 사용하지 않아야 한다는 점에 유의하자.

테이블 구조: 역정규화

수많은 조인을 불러일으키는 쿼리에 대해서는 역정규화를 고려할 수 있다.

역정규화를 토대로 수많은 조인으로 인해 발생하는 부하를 한 번의 조회로 대체함으로써 줄일 수 있기 때문이다.

그러나 역정규화는 중복된 특정 값을 여러 테이블에 적재하는 만큼, N개의 테이블에 대해서 데이터를 업데이트해야 하는 상황을 낳아 더 큰 쓰기 부하를 발생시킬 수도 있다.

DB 분산: 샤딩 / 파티셔닝

샤딩과 파티셔닝은 하나의 테이블을 논리적 또는 물리적으로 여러 개로 쪼개는 방법이다.

데이터가 매우 많은 테이블의 경우 풀 스캔은 효율의 관점에서 끔찍한 상황을 불러일으킬 수 있다.

이렇게 하나의 테이블에 일어나는 부하를 분산하기 위해 하나의 테이블을 여러 개의 서브 셋으로 분할할 수 있다.

파티셔닝의 경우 동일한 테이블을 단일 DB 서버 내에서 논리적 분할해, 읽기/쓰기에 대한 성능 개선을 가질 수 있다.

샤딩은 동일한 테이블을 여러 개의 물리적 서버 내에서 분할해, 파티셔닝의 장점을 그대로 가져가면서 특정 테이블의 부하가 전체 장애로 이어지지 않게 하는 장점 또한 지닌다.

다만 다중 서버로 분할된 만큼 확장된 테이블에 대해 조인 연산 등의 처리는 파티셔닝보다 어렵고, 분할을 위한 샤드 키를 적절하게 선택할 수 있어야 한다.

DB 분산: Master-Slave DB 구성

데이터베이스의 구성 자체를 Master-Slave로 분리해, Master에서만 쓰기가 일어나게 하는 방식이다.

샤딩 / 파티셔닝이 하나의 테이블을 N개로 분할하는 것이었다면, Master-Slave는 하나의 동일 테이블을 N개로 복제하는 것이다.

이를 통해 읽기 작업은 Slave에서 처리하고, 해당 읽기를 진행하는 동안 이 과정에서 Master에서의 쓰기 작업에 대해 락이 걸리지 않아 읽기 성능이 향상될 수 있다.

다만, Master DB 변경을 Slave DB에 업데이트해주는 비용 또한 고려해야 하며, 잘못 구성되었을 경우 데이터 정합성을 해치는 값을 반환할 수 있다는 점을 유의해야 한다.

Scale Up: 아키텍처 성능을 보완하기

어쩌면 최후의 수단, 혹은 당장 급할 때 바로 사용할 수 있는 카드이다.

Scale Up을 통해서 DB 서버의 성능을 높여 하나의 쿼리에 대해 응답 속도를 가속하는 방식이다.

해도해도 이 성능의 서버에서는 절대 속도가 안 나와! 하는 케이스에서는 어쩔 수 없이 사용해야 하는 것으로 보인다.

Memory DB 캐싱하기 - NoSQL

아예 쿼리를 태우지 않는 방법도 있다. 디스크에서의 읽기를 제거하는 것이다.

레디스나 MongoDB등의 NoSQL Memory DB의 값을 먼저 반환함으로써 디스크 탐색 시간을 없애는 것이다.

물론 이 방법의 경우 테이블의 데이터가 기본적으로 크게 변하지 않는다는 전제를 필요로 한다. 따라서 데이터가 상대적으로 변경되지 않는 상황에서 유용할 것이다.

또한 디스크 DB 값 갱신 시 메모리 DB에도 값이 갱신되어야 데이터의 정합성을 유지할 수 있다.


어떤 방식을 선택하느냐는 나의 몫, 선택하는 개발자의 몫일 것이다.

이 방식들은 데이터의 양과 확장성, 도메인 방식과 비즈니스 로직에 따라 선택되어야 할 것이며, 이를 위해 각각의 장단점을 고려할 수 있어야 한다.

여러 가지 방향을 잘 배합해, 현재 상황에 걸맞은 방식을 택할 수 있다면 좋겠다.

참고

[mysql] 인덱스 정리 및 팁

Who is?

금융과 소비자의 교두보가 되고 싶은 개발자.