메모리 읽기가 최근 메모리 쓰기에 의존하는 경우 성능이 떨어짐
load unit
은 메모리 읽기 시 store unit
의 store buffer
를 확인하고, 주소가 일치하는 엔트리가 존재하면 retrieve
해서 load operation
의 결과로 사용
High-Level Design
적합한 알고리즘, 자료구조 사용
Basic coding principles
optimization blocker
피하기
과도한(중복된) 함수 호출을 제거 (연산을 루프 밖으로 꺼내기, 효율성을 위해 modularity
와의 타협을 선택적으로 수용)
필요 없는 메모리 참조 제거
Low-level optimizations
하드웨어의 능력을 최대한 끌어내기 위해 코드 구조화
loop unrolling
, ILP
를 높이기 위한 방법(multiple accumulators
, reassociation
등), conditional data transfer
를 가능하게 하기 위해 조건 연산을 functional style
로 작성
가상 칼럼
을 이용한 인덱스함수
를 이용한 인덱스하나의 데이터 레코드가 여러 개의 키 값을 가질 수 있는 형태의 인덱스
JSON
배열 타입 필드에 저장된 원소들에 대한 인덱스
MEMBER OF
, JSON_CONTAINS
, JSON_OVERLAPS
와 같은 함수를 이용해서 검색해야 인덱스를 활용 가능
InnoDB
스토리지 엔진에만 존재
프라이머리 키 값에 의해 레코드의 저장 위치가 결정됨, 즉 프라이머리 키 값이 변경되면 해당 레코드의 물리적인 저장 위치가 바뀜
클러스터링 키 선택 우선순위
프라이머리 키 -> NOT NULL 옵션의 유니크 인덱스
중 첫 번째 인덱스 -> 내부적으로 생성한 대체 키
MyISAM
테이블의 경우 데이터 레코드가 INSERT
될 때 데이터 파일의 끝 또는 임의의 빈 공간에 저장되고, 한 번 저장된 위치는 절대 바뀌지 않음, 레코드가 저장된 주소(ROWID)는 MySQL 내부적으로 레코드를 식별하는 아이디로 인식됨
MyISAM
테이블의 인덱스는 ROWID
를 사용해서 실제 데이터 레코드를 찾음
InnoDB 테이블의 세컨더리 인덱스는 해당 레코드가 저장된 주소가 아닌 프라이머리 키를 저장하고, 인덱스 검색 시 프라이머리 키 값 확인 후 다시 검색해서 최종 레코드를 찾음
프라이머리 키로 검색할 때 처리 성능 매우 빠름 (특히 범위 검색)
테이블의 모든 세컨더리 인덱스가 프라이머리 키를 가지고 있으므로 커버링 인덱스
로 처리할 수 있는 경우가 많아짐
클러스터링 키 값의 크기가 큰 경우 세컨더리 인덱스 크기도 커짐
세컨더리 인덱스를 통해 검색하는 경우 프라이머리 키로 다시 한 번 검색해야 하므로 처리 속도가 느림
INSERT
시 프라이머리 키에 의해 레코드 저장 위치가 결정되므로 처리 속도가 느림
프라이머리 키 변경 시 레코드를 DELETE
하고 INSERT
하는 작업이 필요하므로 처리 속도가 느림
결국 장점은 빠른 읽기, 단점은 느린 쓰기
인데, OLTP
에서는 쓰기 읽기 비율이 2:8 ~ 1:9
이므로 느린 쓰기 감수 가능
유니크 인덱스와 일반 세컨더리 인덱스는 구조상 아무런 차이가 없음
읽기 성능 차이는 미미함
쓰기 성능은 유니크 인덱스가 떨어짐 (중복 체크 과정이 필요, InnoDB
의 경우 체인지 버퍼
를 사용해서 인덱스 쓰기를 미루는데, 유니크 인덱스는 중복 체크를 바로 해야 하므로 작업 버퍼링이 불가능함
)
InnoDB
스토리지 엔진에서만 생성 가능
외래키 제약이 설정되면 자동으로 인덱스 생성
자식 테이블 레코드의 외래키 칼럼이 변경되는 경우 부모 테이블 해당 레코드에 읽기 잠금을 걸어야 함 (해당 참조키가 존재하는지 체크)
ON DELETE CASCADE
조건이 걸려 있는 경우 부모 테이블 레코드 삭제 시 연관된 자식 테이블 레코드 쓰기 잠금이 필요