콘텐츠로 이동

2024 12 18

2024-12-18

MySQL Unique Key 단점

참고: https://sheerheart.tistory.com/entry/MySQL-%ED%95%98%EA%B8%B0-%EC%89%AC%EC%9A%B4-%EC%8B%A4%EC%88%98%EC%99%80-Tip%EC%97%90-%EB%8C%80%ED%95%9C-%EC%86%8C%EA%B0%9C

  1. 다중 INSERT/UPDATE 성능 이슈

    • 인덱스 유지 비용 증가
      • 다량의 데이터를 빈번하게 갱신하는 경우, 성능 저하로 이어질 수 있음
    • 잠금(Lock) 충돌 가능성
      • UNIQUE KEY 검사를 위해 해당 인덱스 페이지를 잠감함.
      • 동시에 여러 트랜잭션이 INSERT/UPDATE 하면, 경합이 일어날 가능성이 커짐
      • 병목 구간이 발생할 수 있음
  2. 중복 예외 처리 필요

  3. NULL값 처리에 대한 오해 가능성

    • MySQL에서는 'UNIQUE + NULL' 허용함
    • UNIQUE KEY가 걸린 칼럼 여러개에 NULL 값을 허용함 (MySQL 고유동작)
  4. 복합 유니크 키의 복잡성

    • 여러 칼럼을 묶어 UNIQUE KEY로 설정 가능 -> 성능/사용상의 복잡성이 단순 단일 컬럼보다 더 큼
      • 컬럼 중 하나를 변경 시, UNIQUE 위반 가능성도 커짐
    • 복합 인덱스를 제대로 활용할 수 있도록 쿼리를 잘 짜야함
  • Tips
    • Unique Index라고 타 Index 보다 성능이 좋은 것은 아님. (그저 unique는 제약 사항)
    • MySQL의 인덱스의 끝에 PK 컬럼이 추가됨 (클러스터링 인덱스)
      • 따라서 많은 키(복합키)로 PK 구성하는 것은 불리할 수 있음
      • auto increment로 PK 설정하고, 필요 시 다른 인덱스 추가하는 것이 더 나을 듯
    • InnoDB의 레코드 락은 레코드를 잠그는 것이 아니라, 인덱스를 잠금 (넥스트 키 락)
      • Update/Delete 시, 변경해야 할 레코드를 찾기 위해 검색한 인덱스의 레코드가 모두 잠김
      • 예시)

        CREATE TABLE employees (
            emp_no int NOT NULL,
            first_name varchar(14) NOT NULL,
            last_name varchar(16) NOT NULL,
            hire_date date,
            PRIMARY KEY (emp_no),
            KEY idx_first_name(first_name)
        );
        
        UPDATE employees SET hire_date = NOW()
        WHERE first_name = 'Joel' AND last_name = 'Jo'
        

        • 해당 경우 first_name = 'Joel'인 모든 레코드가 잠기게 된다
        • 심지어 idx_first_name도 없다면, 테이블 풀 스캔 하면서 Update 함 -> 테이블의 모든 레코드 잠김
          • MySQL의 Group By는 기본적으로 그룹핑 컬럼 순서대로 정렬