일단 데이터베이스의 성능 튜닝의 관건은 어떻게 디스크 I/O를 줄일 것이냐 일 때가 상당히 많다. CPU나 메모리는 대부분 전자식 장치지만 하드 디스크 드라이브는 기계식 장치이다. 그래서 데이터베이스 서버에서는 항상 디스크 장치가 병목이 된다. 물론 플래시 메모리를 장착하여 디스크의 성능을 높인 SSD를 장착한다면 병목은 하드 디스크 보다는 줄어들겠지만, 디스크의 헤더를 움직이지 않은 순차 데이터 처리의 경우에는 두 디스크가 큰 성능 차이를 보이진 않는다. 인덱스란?인덱스는 디스크 혹은 메모리에 저장되어 있는 레코드에 빠르게 접근하기 위해 "정렬된" 데이터들이다. 인덱스는 정렬되어 있어야 한다 라는 중요한 특성을 가진다. 인덱스가 정렬되어 있지 않다면 인덱스의 데이터가 늘어남에 따라 탐색속도는 점점 저하..
Database
데이터베이스 작업에서 발생할 수 있는 동시성문제를 처리하기 위해 MySQL에서 지원하는 공유(Shared)락, 배타(Exclusive)락과 동시성문제를 처리하는 방식인 낙관적(Optimistic)락, 비관적(Pessimistic)락을 정리하려 한다. 모든 설명은 MySQL 8.0을 기반으로 한다. 동시성 문제 동시성 문제는 멀티 스레드, 프로세스 작업에서 개발자가 해결해야 하는 문제이다. 하나의 공유 자원에 두 스레드가 동시에 접근하여 데이터를 변경하는 작업을 처리하는 경우 발생할 수 있는 문제점들이다. 한 가지 예시를 들어보자. 웹 쇼핑몰에서 아이패드 1개를 판매하기 위해 상품을 등록했다. 아주 매력적인 가격이었기에 10명의 사용자가 동시에 결제를 진행한다고 가정한다. 동시성 처리를 하지 않은 경우라면..
테이블 컬럼의 각 데이터 타입을 결정할 때는 아래의 사항을 유의해야 한다. 저장되는 값의 성격에 맞는 최적의 타입을 선정 가변 길이 컬럼은 최적의 길이를 지정 조인 조건으로 사용되는 컬럼은 똑같은 데이터 타입으로 선정 컬럼의 데이터 타입을 결정할 때 실제 저장되는 값의 특성을 고려하기 보다는 저장되는 값의 최대 길이를 기준으로 컬럼의 길이를 선택하는 것이 일반적이다. 하지만 컬럼의 크기가 너무 무분별하게 커진다면 디스크 공간을 많이 차지할 것이고 해당 컬럼이 인덱스라면 검색 효율도 떨어질 것이다. ☁️ ENUM 과 SET ENUM 과 SET을 사용하면 문자열 값을 내부적인 작엽을 통해 숫자 값으로 매핑하여 관리한다. 레코드의 타입이나 상태와 같은 코드 형태의 컬럼(ex. 상품 유형 코드 E(전자), A(..
테이블 컬럼의 각 데이터 타입을 결정할 때는 아래의 사항을 유의해야 한다. 저장되는 값의 성격에 맞는 최적의 타입을 선정 가변 길이 컬럼은 최적의 길이를 지정 조인 조건으로 사용되는 컬럼은 똑같은 데이터 타입으로 선정 컬럼의 데이터 타입을 결정할 때 실제 저장되는 값의 특성을 고려하기 보다는 저장되는 값의 최대 길이를 기준으로 컬럼의 길이를 선택하는 것이 일반적이다. 하지만 컬럼의 크기가 너무 무분별하게 커진다면 디스크 공간을 많이 차지할 것이고 해당 컬럼이 인덱스라면 검색 효율도 떨어질 것이다. ☁️ 문자열 (CHAR, VARCHAR) 두 타입 모두 문자열을 저장한다는 공통점을 가진다. CHAR 타입은 고정길이이며, VARCHAR 타입은 가변길이로 관리된다. CHAR(1), VARCHAR(1) 은 모두..
☁️ 파티션 파티션 기능은 논리적인 하나의 테이블을 물리적으로 여러 개의 테이블로 분리해서 관리하는 기능이다. 주로 대용량의 테이블을 물리적으로 여러 개의 소규모 테이블로 분산하는 목적으로 사용한다. 또한 파티션을 분리하면 필요한 파티션에만 접근할 수 있다는 장점을 취할 수 있다. 대용량 테이블을 분산하여 저장한다면 조회 쿼리의 성능이 좋아지게 된다. 하지만 잘못된 쿼리를 사용하는 경우 오히려 쿼리의 성능이 나빠질 수 있다. 파티션 사용 시 유의해야 할 사항을 알아보자. 파티션을 사용하는 이유 테이블의 데이터가 많다고 해서 무조건 파티션을 적용하는 것은 옳지 않다. 테이블의 크기가 커져 인덱스가 메모리보다 커지는 경우 혹은 데이터 특성상 주기적인 삭제작업이 필요한 경우 등에 파티션을 사용하면 좋다. 인덱..
💡 해당 포스팅은 참고용으로 MySQL 사용 편리성을 위해 쿼리나 명령어, Real MySQL의 쿼리 사용 팁들을 단순 정리한다. ☁️ INSERT 온라인 트랜잭션 서비스에서 INSERT 문장은 대부분 1건 또는 소량의 레코드를 추가하기에 성능에 대해 고려할 부분이 많지 않다. 한 번의 많은 INSERT 문이 실행되는 경우 쿼리 문장 보다는 테이블 구조가 성능에 영향을 미치는 경우가 대다수이다. 하지만 많은 경우 INSERT의 성능과 SELECT의 성능을 동시에 빠르게 만들 수 있는 테이블 구조는 없다. 그래서 INSERT와 SELECT 성능을 어느 정도 타협하면서 테이블 구조를 설계해야 한다 - 중에서 유용한 기능 INSERT IGNORE: INSERT 실행 시 테이블의 유니크 한 컬럼의 값이 중복되는..
인덱스 레인지 스캔은 인덱스를 탐색하는(Index Seek) 단계와 인덱스를 스캔하는(Index Scan) 과정으로 구분할 수 있다. 탐색 단계는 B-Tree를 통해 특정 인덱스 혹은 범위를 탐색하는 작업이고, 스캔 단계는 리프노드를 순차적으로 읽는 작업이다. 일반적으로 인덱스를 통해 가져오는 레코드는 소량이다. 따라서 스캔 작업 보다는 탐색 작업이 상대적으로 부하가 크다. ☁️ 드라이빙 테이블과 드리븐 테이블 두 개 이상의 테이블을 JOIN하는 과정에서 드라이빙 테이블과 드리븐 테이블이 구분된다. 보통 드라이빙 테이블을 읽을 때는 인덱스 탐색 작업을 한 번만 수행한 뒤 스캔작업만 수행하면 되지만 드리븐 테이블은 탐색과 스캔 작업을 드라이빙 테이블에서 읽은 레코드 수만큼 진행한다.따라서 드라이빙 테이블과..
☁️ 인덱스 사용의 기본적인 유의사항 기본적으로 인덱스를 사용하려면 인덱스된 컬럼의 값(인덱스 키값) 자체를 변환하지 않고 사용해야 한다. 해당 조건은 타입이 동일해야 한다는 조건을 포함한다. 자동 타입 변경으로 인해 인덱스를 사용하지 못하는 경우도 유의해야 한다. 예를 들어 아래와 같은 쿼리는 인덱스를 사용하지 못한다. -- employees.salary가 단일 컬럼 인덱스로 선언되었다고 가정 SELECT * FROM employees WHERE salary*10=12000; -- 아래 처럼 변경하면 인덱스를 사용할 수 있다. SELECT * FROM employees WHERE salary=12000/10; 만약 특정 컬럼을 변환한 값에 의한 검색이 빈번하게 발생하는 경우 가상 컬럼을 통해 인덱스를 ..