요청된 쿼리는 같은 결과를 반환하지만, 내부적으로 그 결과를 어떻게 만들어낼 것인지에 대한 방법은 매우 다양하다. 따라서 어떤 방법이 최적이고 최소의 비용이 소모되는지 결정해야 한다. MySQL에서는 테이블의 데이터가 어떤 분포로 저장돼 있는지 통계 정보를 참조해 최적의 실행 계획을 수립한다. 대부분의 DBMS에서도 옵티마이저가 이러한 기능을 담당하고 있다. 쿼리 실행 절차 쿼리가 실행되는 과정은 크게 세 단계로 나눌 수 있다. 요청된 SQL 문장을 쪼개서 MySQL 서버가 이해할 수 있는 수준으로 분리(파스 트리) SQL 파싱 단계로 SQL 파서 모듈로 처리 SQL 문법 오류(Syntax Error)가 이 단계에서 걸러짐 SQL 파스 트리 생성 SQL의 파싱 정보(파스 트리)를 확인해 어떤 테이블을 읽..
멀티 밸류 인덱스 전문 검색 인덱스를 제외한 모든 인덱스는 인덱스 키와 데이터 레코드가 1:1 관계를 가진다. 하지만 멀티 밸류 인덱스는 하나의 데이터 레코드가 여러 개의 키 값을 가질 수 있는 형태의 인덱스다. JSON의 배열 타입의 필드에 저장된 원소들에 대한 인덱스를 지원하기 위해 MySQL 8.0 버전에서 업그레이드됐다. // 멀티 밸류 인덱스 생성 CREATE TABLE user ( user_id BIGINT AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(10), last_name VARCHAR(10), credit_info JSON, INDEX mx_creditscores ( (CAST(credit_info->'$.credit_scores' AS UNSIG..
R-Tree 인덱스 R-Tree 인덱스는 2차원의 데이터를 저장하는 인덱스이다. R-Tree 인덱스를 구성하는 컬럼의 값은 2차원의 공간 개념 값으로 MySQL 공간 인덱스에 이용된다. 공간 인덱스는 위치 기반의 서비스를 구현할 때 주로 사용되며 MySQL의 공간 확장을 이용해 간단하게 구현할 수 있다. MySQL의 공간 확장에는 크게 세 가지 기능이 포함돼 있다. 공간 데이터를 저장할 수 있는 데이터 타입 (POINT, LINE, POLYGON, GEOMETRY) 공간 데이터 검색을 위한 공간 인덱스 (R-Tree 알고리즘) 공간 데이터의 연산 함수 (ST_Contains(), ST_Within()) 구조 및 특성 MySQL은 공간 정보의 저장 및 검색을 위해 POINT, LINE, POLYGON, G..
B-Tree 인덱스를 통한 데이터 읽기 어떤 경우에 인덱스를 사용하도록 유도할지, 사용하지 못하게 할지 판단하려면 MySQL이 어떻게 인덱스를 이용해 실제 레코드를 읽어 내는지 알아야 한다. 이제 MySQL이 인덱스를 이용하는 방법 세 가지를 알아보자. 인덱스 레인지 스캔 인덱스 레인지 스캔은 가장 대표적인 인덱스 접근 방식으로, 검색해야 할 인덱스의 범위가 결정됐을 때 사용하는 방식이다. 뒤에 설명할 두 가지 인덱스 접근 방식보다는 빠른 방법이다. 다음 쿼리를 예제로 살펴보자. SELECT * FROM employees WHERE first.name BETWEEN 'Ebbe' AND 'Gad'; 위 쿼리가 실행되면 아래 그림과 같이 루트 노드에서부터 브랜치 노드를 거쳐 최종적으로 리프 노드까지 찾아 들..
인덱스는 컬럼의 값과 해당 레코드가 저장된 주소를 키와 값의 쌍으로 삼아 주어진 순서로 미리 정렬해 저장해 두고 원하는 결과를 최대한 빠르게 찾아갈 수 있도록 한다. 인덱스를 쉽게 설명해 책으로 비유하자면 색인으로 설명할 수 있다. 책의 색인을 통해 알아낼 수 있는 페이지 번호는 데이터 파일에 저장된 레코드의 주소에 비유될 것이고, 해당 페이지의 내용은 데이터 파일에 비유할 수 있다. 또 색인과 DBMS 인덱스의 중요한 공통점은 바로 정렬이다. 색인의 내용이 너무 많으면 원하는 검색어를 찾아내는데 시간이 걸릴 것이다. 이때 색인의 정보가 정렬이 되어있다면(ㄱ, ㄴ, ㄷ, …) 원하는 정보를 최대한 빠르게 찾아갈 수 있다. 인덱스도 마찬가지로 컬럼의 값을 주어진 순서로 미리 정렬해서 보관하므로 원하는 결과..
트랜잭션의 격리 수준이란 여러 트랜잭션이 동시에 처리될 때 특정 트랜잭션이 다른 트랜잭션에서 변경하거나 조회하는 데이터를 볼 수 있게 허용할지 말지를 결정하는 것이다. 격리 수준은 크게 4가지로 나뉜다. READ-UNCOMMITTED READ-COMMITTED REAPEATABLE-READ SERIALIZABLE 4개의 격리 수준에서 순서대로 뒤로 갈수록 각 트랜잭션 간의 데이터 고립 정도가 높아지며, 동시 처리 성능도 떨어진다. 일반적인 온라인 서비스 용도의 데이터베이스는 READ-COMMITTED나 REAPEATABLE-READ 중 하나를 사용한다. 이 중 MySQL의 기본 격리 수준은 REAPEATABLE-READ이다. READ-UNCOMMITTED 격리 수준 READ-UNCOMMITTED 격리 수..
트랜잭션은 작업의 완전성을 보장해주는 것이다. 즉, 논리적인 작업 셋을 모두 완벽하게 처리하거나, 처리하지 못하는 경우 롤백시켜 작업의 일부만 적용되는 현상을 방지하기 위한 기술이다. 따라서 트랜잭션은 데이터의 정합성을 보장하기 위한 기능이라고 볼 수 있다. 잠금(LOCK)은 트랜션과 비슷한 개념 같지만 사실 동시성을 제어하기 위한 기능이다. 잠금 없이 여러 커넥션이 하나의 데이터를 동시에 변경한다면 어떻게 될까? 그 데이터의 값은 예측할 수 없게 될 것이다. 한 시점에 하나의 커넥션만 데이터를 변경할 수 있도록 동시성을 제어해주는 역할이 잠금(LOCK)의 역할이라고 볼 수 있다. MySQL에서의 트랜잭션 앞서 설명했듯, 트랜잭션은 작업 셋을 100%(Commit) 또는 0%(Rollback)로 만들어 ..
언두 로그 언두 로그란 트랜잭션과 격리 수준을 보장하기 위해 DML(INSERT, UPDATE, DELETE)로 변경되기 이전 버전의 데이터를 별도로 백업해둔 데이터를 말한다. 언두 로그의 데이터는 크게 트랜잭션의 롤백 대비용 데이터와 격리 수준을 유지하면서 높은 동시성을 제공하기 위한 용도로 사용된다. 트랜잭션 보장 트랜잭션이 롤백되면 언두 로그에 백업해둔 이전 버전의 데이터를 이용해 복구한다. 격리 수준 보장 데이터를 변경하는 도중 다른 커넥션에서 데이터를 조회하면 격리 수준에 맞게(READ_COMMITTED, REPEATABLE READ) 언두 로그에 백업해둔 데이터를 읽어서 반환한다. 언두 로그는 InnoDB 스토리지 엔진에서 매우 중요한 역할을 담당하지만 그만큼의 관리 비용도 많이 필요하다. 언..
InnoDB 스토리지 엔진 MySQL의 스토리지 엔진 중에서 유일하게 레코드 기반의 잠금을 제공하며, 높은 동시성 처리가 가능하고 안정적이며 성능이 뛰어난 스토리지 엔진이다. 프라이머리 키에 의한 클러스터링 InnoDB의 모든 테이블은 프라이머리 키 값의 순서대로 디스크에 저장된다. 모든 세컨더리 인덱스는 레코드 주소 대신 프라이머리 키의 값을 논리적인 주소로 사용한다. 프라이머리 키는 클러스터링 인덱스이기 때문에 프라이머리 키를 이용한 레인지 스캔은 상당히 빨리 처리될 수 있다. 결과 적으로 쿼리의 실행 계획에서 다른 보조 인덱스보다 프라이머리 키가 인덱스로 선택될 확률이 높다. 외래키 지원 InnoDB 스토리지 엔진 레벨에서만 지원한다. MyISAM이나 MEMORY 테이블에서는 사용할 수 없다. 외래..