티스토리

개발일기
검색하기

블로그 홈

개발일기

hyunsb.tistory.com/m

Github: Hyunsb

구독자
5
방명록 방문하기

주요 글 목록

  • MySQL 8.0 인덱스에 대한 고찰 일단 데이터베이스의 성능 튜닝의 관건은 어떻게 디스크 I/O를 줄일 것이냐 일 때가 상당히 많다. CPU나 메모리는 대부분 전자식 장치지만 하드 디스크 드라이브는 기계식 장치이다. 그래서 데이터베이스 서버에서는 항상 디스크 장치가 병목이 된다. 물론 플래시 메모리를 장착하여 디스크의 성능을 높인 SSD를 장착한다면 병목은 하드 디스크 보다는 줄어들겠지만, 디스크의 헤더를 움직이지 않은 순차 데이터 처리의 경우에는 두 디스크가 큰 성능 차이를 보이진 않는다. 인덱스란?인덱스는 디스크 혹은 메모리에 저장되어 있는 레코드에 빠르게 접근하기 위해 "정렬된" 데이터들이다. 인덱스는 정렬되어 있어야 한다 라는 중요한 특성을 가진다. 인덱스가 정렬되어 있지 않다면 인덱스의 데이터가 늘어남에 따라 탐색속도는 점점 저하.. 공감수 2 댓글수 1 2024. 4. 13.
  • 동시성 문제 해결 Lock: Shared, Exclusive, Pessimistic, Optimistic 데이터베이스 작업에서 발생할 수 있는 동시성문제를 처리하기 위해 MySQL에서 지원하는 공유(Shared)락, 배타(Exclusive)락과 동시성문제를 처리하는 방식인 낙관적(Optimistic)락, 비관적(Pessimistic)락을 정리하려 한다. 모든 설명은 MySQL 8.0을 기반으로 한다. 동시성 문제 동시성 문제는 멀티 스레드, 프로세스 작업에서 개발자가 해결해야 하는 문제이다. 하나의 공유 자원에 두 스레드가 동시에 접근하여 데이터를 변경하는 작업을 처리하는 경우 발생할 수 있는 문제점들이다. 한 가지 예시를 들어보자. 웹 쇼핑몰에서 아이패드 1개를 판매하기 위해 상품을 등록했다. 아주 매력적인 가격이었기에 10명의 사용자가 동시에 결제를 진행한다고 가정한다. 동시성 처리를 하지 않은 경우라면.. 공감수 0 댓글수 0 2024. 3. 19.
  • 데이터 타입: ENUM, BLOB, JSON, 가상 컬럼 테이블 컬럼의 각 데이터 타입을 결정할 때는 아래의 사항을 유의해야 한다. 저장되는 값의 성격에 맞는 최적의 타입을 선정 가변 길이 컬럼은 최적의 길이를 지정 조인 조건으로 사용되는 컬럼은 똑같은 데이터 타입으로 선정 컬럼의 데이터 타입을 결정할 때 실제 저장되는 값의 특성을 고려하기 보다는 저장되는 값의 최대 길이를 기준으로 컬럼의 길이를 선택하는 것이 일반적이다. 하지만 컬럼의 크기가 너무 무분별하게 커진다면 디스크 공간을 많이 차지할 것이고 해당 컬럼이 인덱스라면 검색 효율도 떨어질 것이다. ☁️ ENUM 과 SET ENUM 과 SET을 사용하면 문자열 값을 내부적인 작엽을 통해 숫자 값으로 매핑하여 관리한다. 레코드의 타입이나 상태와 같은 코드 형태의 컬럼(ex. 상품 유형 코드 E(전자), A(.. 공감수 1 댓글수 0 2024. 2. 3.
  • 데이터 타입: 문자열, 숫자, 날짜 테이블 컬럼의 각 데이터 타입을 결정할 때는 아래의 사항을 유의해야 한다. 저장되는 값의 성격에 맞는 최적의 타입을 선정 가변 길이 컬럼은 최적의 길이를 지정 조인 조건으로 사용되는 컬럼은 똑같은 데이터 타입으로 선정 컬럼의 데이터 타입을 결정할 때 실제 저장되는 값의 특성을 고려하기 보다는 저장되는 값의 최대 길이를 기준으로 컬럼의 길이를 선택하는 것이 일반적이다. 하지만 컬럼의 크기가 너무 무분별하게 커진다면 디스크 공간을 많이 차지할 것이고 해당 컬럼이 인덱스라면 검색 효율도 떨어질 것이다. ☁️ 문자열 (CHAR, VARCHAR) 두 타입 모두 문자열을 저장한다는 공통점을 가진다. CHAR 타입은 고정길이이며, VARCHAR 타입은 가변길이로 관리된다. CHAR(1), VARCHAR(1) 은 모두.. 공감수 3 댓글수 0 2024. 2. 2.
  • 파티션 ☁️ 파티션 파티션 기능은 논리적인 하나의 테이블을 물리적으로 여러 개의 테이블로 분리해서 관리하는 기능이다. 주로 대용량의 테이블을 물리적으로 여러 개의 소규모 테이블로 분산하는 목적으로 사용한다. 또한 파티션을 분리하면 필요한 파티션에만 접근할 수 있다는 장점을 취할 수 있다. 대용량 테이블을 분산하여 저장한다면 조회 쿼리의 성능이 좋아지게 된다. 하지만 잘못된 쿼리를 사용하는 경우 오히려 쿼리의 성능이 나빠질 수 있다. 파티션 사용 시 유의해야 할 사항을 알아보자. 파티션을 사용하는 이유 테이블의 데이터가 많다고 해서 무조건 파티션을 적용하는 것은 옳지 않다. 테이블의 크기가 커져 인덱스가 메모리보다 커지는 경우 혹은 데이터 특성상 주기적인 삭제작업이 필요한 경우 등에 파티션을 사용하면 좋다. 인덱.. 공감수 0 댓글수 1 2024. 2. 2.
  • Real MySQL 8.0의 쿼리 팁 💡 해당 포스팅은 참고용으로 MySQL 사용 편리성을 위해 쿼리나 명령어, Real MySQL의 쿼리 사용 팁들을 단순 정리한다. ☁️ INSERT 온라인 트랜잭션 서비스에서 INSERT 문장은 대부분 1건 또는 소량의 레코드를 추가하기에 성능에 대해 고려할 부분이 많지 않다. 한 번의 많은 INSERT 문이 실행되는 경우 쿼리 문장 보다는 테이블 구조가 성능에 영향을 미치는 경우가 대다수이다. 하지만 많은 경우 INSERT의 성능과 SELECT의 성능을 동시에 빠르게 만들 수 있는 테이블 구조는 없다. 그래서 INSERT와 SELECT 성능을 어느 정도 타협하면서 테이블 구조를 설계해야 한다 - 중에서 유용한 기능 INSERT IGNORE: INSERT 실행 시 테이블의 유니크 한 컬럼의 값이 중복되는.. 공감수 1 댓글수 0 2024. 2. 1.
  • JOIN 절에서 INDEX 사용 시 유의할 점 인덱스 레인지 스캔은 인덱스를 탐색하는(Index Seek) 단계와 인덱스를 스캔하는(Index Scan) 과정으로 구분할 수 있다. 탐색 단계는 B-Tree를 통해 특정 인덱스 혹은 범위를 탐색하는 작업이고, 스캔 단계는 리프노드를 순차적으로 읽는 작업이다. 일반적으로 인덱스를 통해 가져오는 레코드는 소량이다. 따라서 스캔 작업 보다는 탐색 작업이 상대적으로 부하가 크다. ☁️ 드라이빙 테이블과 드리븐 테이블 두 개 이상의 테이블을 JOIN하는 과정에서 드라이빙 테이블과 드리븐 테이블이 구분된다. 보통 드라이빙 테이블을 읽을 때는 인덱스 탐색 작업을 한 번만 수행한 뒤 스캔작업만 수행하면 되지만 드리븐 테이블은 탐색과 스캔 작업을 드라이빙 테이블에서 읽은 레코드 수만큼 진행한다.따라서 드라이빙 테이블과.. 공감수 0 댓글수 0 2024. 1. 31.
  • 인덱스 사용하기: WHERE, GROUP BY, ORDER BY ☁️ 인덱스 사용의 기본적인 유의사항 기본적으로 인덱스를 사용하려면 인덱스된 컬럼의 값(인덱스 키값) 자체를 변환하지 않고 사용해야 한다. 해당 조건은 타입이 동일해야 한다는 조건을 포함한다. 자동 타입 변경으로 인해 인덱스를 사용하지 못하는 경우도 유의해야 한다. 예를 들어 아래와 같은 쿼리는 인덱스를 사용하지 못한다. -- employees.salary가 단일 컬럼 인덱스로 선언되었다고 가정 SELECT * FROM employees WHERE salary*10=12000; -- 아래 처럼 변경하면 인덱스를 사용할 수 있다. SELECT * FROM employees WHERE salary=12000/10; 만약 특정 컬럼을 변환한 값에 의한 검색이 빈번하게 발생하는 경우 가상 컬럼을 통해 인덱스를 .. 공감수 0 댓글수 0 2024. 1. 31.
  • 실행 계획 정리 쿼리 튜닝을 진행하며 얻은 팁과 정리를 계속해서 추가할 예정이다. 실행 계획 정리 | Notion 쿼리 튜닝을 진행하며 얻은 팁과 정리를 계속해서 추가할 예정이다. hyunsb.notion.site 참고하면 좋은 글 [SQL튜닝] MySQL 쿼리 튜닝, 쿼리 실행계획, Explain 실행계획을 분석해서 SQL 성능튜닝을 해보자(feat.MySQL) 공감수 0 댓글수 1 2024. 1. 30.
  • 인덱스: 클러스터링, 유니크 등 ☁️ 클러스터링 인덱스 데이터베이스를 조회할 때, 주로 비슷한 값을 통시에 조회하는 경우가 많다고 한다. 이를 착안하여 비슷한 값(보통 프라이머리 키 기준)으로 묶어서 저장하는 것을 클러스터링 인덱스라고 한다. 클러스터링 인덱스는 다른 세컨더리 인덱스와는 다르게 인덱스의 값으로 레코드의 물리적인 주소를 가지고 있다. 레코드는 클러스터링 키 값에 의해 저장위치가 결정되며, 특정 레코드의 클러스터링 키의 데이터가 변경된다면 해당 레코드의 물리적인 위치까지 변경되는 코스트 높은 작업이 수행될 것이다. 이처럼 InnoDB에서 레코드는 클러스터링 인덱스에 상당히 의존적이기에 프라이머리 키를 신중하게 결정해야 한다. InnoDB에서는 각 테이블에 클러스터링 인덱스가 무조건 생성된다. 클러스터링 인덱스는 키 값으로 .. 공감수 1 댓글수 0 2024. 1. 30.
  • 인덱스: B-Tree ☁️ 인덱스 (index) 인덱스는 책의 맨 끝에 있는 찾아보기라고 많이 설명된다. 특정 데이터를 이 찾아보기(인덱스)를 통해 데이터의 주소로 바로 이동할 수 것이다. 인덱스는 인덱스의 칼럼과 해당 레코드가 저장된 주소를 키와 값 쌍으로 찾아보기 쉽게 정렬하여 저장한다. (InnoDB는 레코드 주소가 아닌 PK를 주소처럼 사용) select 문장의 경우 인덱스를 통해 특정 레코드를 검색하는 것이 인덱스 없이 전체 테이블에서 레코드를 검색하는 방식보다 훨씬 빠를 것이다. 하지만 insert, update, delete 문장은 어떨까? 인덱스는 정렬되어 저장된다고 앞서 말했다. 레코드의 변경이 생기는 insert, update, delete 문장에 의해 인덱스와 연관이 있는 레코드에 변경이 생기는 경우 인덱.. 공감수 0 댓글수 1 2024. 1. 29.
  • MySQL 엔진과 InnoDB 엔진의 잠금 ☁️ MySQL 엔진의 잠금 MySQL에서 사용되는 잠금은 스토리지 엔진 레벨의 잠금과 MySQL 엔진 레벨의 잠금으로 나눌 수 있다. MySQL 엔진은 스토리지 엔진을 제외한 MySQL 서버의 모든 영역으로 보면되는데, MySQL 엔진 레벨의 잠금은 스토리지 엔진에도 영향을 미치지만, 반대로 스토리지 엔진 레벨의 잠금은 MySQL 엔진에 영향을 미치지 않는다. MySQL 엔진에서 제공하는 락의 종류를 간단하게만 정리하고 넘어가보려 한다. 글로벌 락 (Global Lock) MySQL에서 제공하는 잠금 가운데 가장 범위가 크다. 하나의 세션이 글로벌 락을 획득하면 다른 세션에서의 Select 작업 외의 모든 작업은 글로벌 락의 해제를 기다려야 한다. 이는 MySQL 서버 전체에 대한 락이므로 작업 테이블.. 공감수 0 댓글수 1 2024. 1. 27.
  • 트랜잭션(Transaction)과 격리 수준(Isolation level) ☁️ 트랜잭션 트랜잭션이란 우리가 하나라고 생각하는 작업이다. 예를 들어 나에게 “샤워를 한 뒤 바디로션을 바른다.”는 하나의 작업이다. 엄밀하게 따지면 “샤워를 한다.” 와 “바디로션을 바른다.”로 행동이 나눠지지만 그냥 하나의 작업으로 묶는 것이다. 트랜잭션도 동일하다. “A테이블을 읽고 a레코드가 존재한다면, A테이블의 a레코드를 수정한다.” 라는 두 작업을 하나의 작업으로 인식하게 하는 것이다. 하나의 작업은 반드시 성공(커밋)하거나 하나라도 실패 시 롤백되어야 한다. A테이블을 읽는 작업을 성공하고 a레코드를 수정하는 작업에서 오류가 발생하였다면 롤백되어야 한다. 유의할 점 그런데 여기서 유의해야할 사항이 있다. “과연 A테이블을 읽고 a레코드가 존재한다면, A테이블의 a레코드를 수정한다” 라는.. 공감수 0 댓글수 1 2024. 1. 27.
  • InnoDB 스토리지 엔진 - 지원 기능 아래 포스팅과 이어집니다. InnoDB 스토리지 엔진 - 버퍼 풀과 리두, 언두 로그 ☁️ InnoDB 스토리지 엔진 아키텍처 스토리지 엔진은 MySQL 엔진에서 핸들러에 의해 전달된 명령을 수행하는 엔진이다. 데이터를 메모리에 쓰고 읽는 작업을 수행한다. 이 중 MySQL에서 가장 많이 hyunsb.tistory.com ☁️ 어댑티브 해시 인덱스 InnoDB는 내부적으로 자주 사용되는 데이터에 페이지 대해 자동으로 생성되는 인덱스를 가지고 있다. 보통 테이블 인덱스라고 하면 B-Tree 구조로 생성하는데, 어댑티브 해시 인덱스는 이름처럼 해시 값을 가진다. B-Tree 인덱스는 O(logN)의 빠른 탐색 속도를 가지지만, 수천 개의 스레드가 동시에 이를 처리한다면 속도는 느려질 수 밖에 없다. 이러한 .. 공감수 1 댓글수 1 2024. 1. 26.
  • InnoDB 스토리지 엔진 - 버퍼 풀과 리두, 언두 로그 ☁️ InnoDB 스토리지 엔진 아키텍처 스토리지 엔진은 MySQL 엔진에서 핸들러에 의해 전달된 명령을 수행하는 엔진이다. 데이터를 메모리에 쓰고 읽는 작업을 수행한다. 이 중 MySQL에서 가장 많이 사용되는 엔진은 InnoDB 스토리지 엔진이다. InnoDB 스토리지 엔진은 내부적으로 Buffer pool을 가지고 있어 데이터 캐싱을 지원한다. 또한 쓰기 작업에 대해 지연된 쓰기를 지원하고, 백그라운드 스레드가 주기적으로 더티 페이지를 확인하여 디스크에 데이터를 적재하고 동기화하는 작업을 수행한다. InnoDB 스토리지 엔진은 레코드(튜플) 기반 잠금을 제공한다. 튜플 기반 잠금은 테이블 기반 잠금보다 좁은 범위 락을 사용하고, 각 트랜잭션이 튜플을 기준으로 동작할 수 있기에 높은 동시성 처리가 가.. 공감수 2 댓글수 1 2024. 1. 26.
  • 쿼리 실행 구조와 MySQL 8.0 변경점 ☁️ 쿼리 실행 구조 사용자가 MySQL에 쿼리를 요청하면 MySQL은 아래의 그림과 같은 절차를 수행한다. 쿼리 파서 사용자의 요청으로 들어온 쿼리 문장을 토큰으로 분리하여 트리 형태의 구조(파서 트리)로 만들어 내는 작업을 수행한다. 이 때, 사용자가 요청한 쿼리의 기본 문법 오류가 발견되고 리턴된다. 전처리기 쿼리 파서 과정에서 만들어진 파서 트리를 기반으로 쿼리 문장에 문제점이 있는지 확인한다. 테이블 이름이나 컬럼, 내장 함수 같은 구문에 오류가 있는지 확인하고, 실제로 존재하는 테이블인지 권한상 접근 불가능한 테이블인지 판단 후 오류 검출 시 리턴한다. 옵티마이저 옵티마이저는 MySQL 엔진의 뇌와 같은 존재이다. 쿼리 문장을 더 저렴한 비용으로 빠르게 처리할 수 있는지를 판단하여 실행 계획을.. 공감수 1 댓글수 2 2024. 1. 25.
  • MySQL 아키텍처와 스레딩 ☁️ MySQL 사용이유 Oracle과 비교한 MySQL의 경쟁력은 가격이다. 방대한 양을 저장하고 트래픽을 수용하기에 Oracle RDBMS는 너무 비싸다. MySQL은 Oracle 만큼이나 레퍼런스가 많고 안정적이기에 사용하기에 좋다고 생각한다. ☁️ MySQL 아키텍처 MySQL은 크게 MySQL 엔진과 스토리지 엔진으로 구분할 수 있다. MySQL엔진: 쿼리 파싱, 옵티마이저 등 사용자 요청에 대한 전반적인 처리를 담당한다. 스토리지 엔진: 디스크에 쓰기, 읽기 작업을 수행한다. 스토리지 엔진 마다 수행 방식이 상이하다. MySQL엔진 MySQL 엔진은 클라이언트로부터의 접속 및 쿼리 요청을 처리하는 커넥션 핸들러, SQL파서, 전처리기, 쿼리를 최적화 해주는 옵티마이저가 중심을 이룬다. 스토리지.. 공감수 1 댓글수 2 2024. 1. 25.
    문의안내
    • 티스토리
    • 로그인
    • 고객센터

    티스토리는 카카오에서 사랑을 담아 만듭니다.

    © Kakao Corp.