일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- 바로팜
- allra
- 머신러닝
- 핀테크
- aarrr
- model_selection
- fundbox
- mysql설치 #mysql #mysqluser #mysqlworkbench
- sklearn
- 전환율
- 서말리포켓
- retention
- 리텐션
- 한장으로끝내는비즈니스모델100
- CAC
- 올라
- 활성화
- 데이터분석
- 셀프스토리지
- 퍼널분석
- BM분석
- 인게이지먼트
- 팔방이익구조
- 역설구조
- activation
- 코호트
- pmf
- 선정산서비스
- 비즈니스모델
- 그로스해킹
- Today
- Total
데이터로그😎
[SQL기본] DISTINCT, 제대로 알고 쓰자! 본문
🧠1. 오늘의 궁금증
"SELECT DISTINCT 쿼리 한 줄 짰는데 왜 이렇게 느리죠…?
단순히 중복만 제거하면 되는 거 아닌가요?"
이런 생각, 다들 한 번쯤 해보셨을 겁니다. 저 역시 대용량 데이터를 대상으로 쿼리를 날렸다가 기다림의 끝없는 터널을 경험했고, 그 날 이후 DISTINCT의 작동 원리를 깊게 파고들게 됐습니다. 오늘은 그 궁금증을 풀어보려 합니다.
"왜 DISINCT는 느린가?" 그리고 "어떻게 더 빠르게 만들 수 있을까?"
⚙️2. DISTINCT는 어떻게 작동할까?
SQL에서 DISTINCT는 SELECT 결과에서 중복된 행을 제거하고 고유한 값만 남기는 기능입니다. 겉으로 보기엔 간단하지만, 내부에서는 다음 두 가지 방식 중 하나로 동작합니다.
1. 정렬 기반 제거 (Sort)
- 데이터를 정렬한 후, 앞뒤 행이 같으면 패스
- 간단하지만 정렬 자체의 비용이 꽤 큽니다
2. 해시 기반 제거 (Hash)
- 각 행을 해시 테이블에 저장하고, 이미 존재하는 해시라면 패스
- 보통 정렬보다 빠릅니다 (DB엔진에 따라 선택)
🐢 3. 그럼 왜 느린 걸까?
자, 예시 테이블을 보겠습니다.(employees)
id | department |
1 | HR |
2 | HR |
3 | IT |
4 | Sales |
5 | Sales |
6 | Sales |
이 때, 아래 쿼리를 실행합니다.
SELECT DISTINCT department FROM employees;
DISTINCT를 사용할 때는 대부분 Full Table Scan을 합니다. 즉, 중복 여부를 판단하기 위해 테이블 전체를 한 번 훑는다는 말인데요, 따라서 전체 데이터의 양이 많아질 수록 훑어야 하는 데이터가 많아지기 때문에 distinct의 속도가 느려집니다.
작동 과정
- employees 테이블의 모든 row+column을 읽습니다.(Full Table Scan)
- id도 읽고, department도 읽고, 필요 없는 컬럼도 모두 읽습니다.
- 중복 여부 판단을 위해 정렬 또는 해시 연산 수행
- 정렬: [HR, HR, IT, Sales, Sales, Sales] --> 앞뒤 행이 같으면 제거 --> 결과 반환: [HR, IT, Sales]
문제가 뭘까?
Full Table Scan을 하면서 불필요한 컬럼까지 전부 읽고 비교해야 하니 속도가 느려집니다.
🚀 4. 성능 향상, 어떻게 할까?
데이터가 많을 때 DISTINCT의 느린 속도를 보완할 수 있는 방법은 무엇이 있을까요?
4.1. 인덱스 사용
CREAT INDEX 문을 통해 인덱스를 생성한 후 SELECT 쿼리를 실행하면 DISTINCT의 작동 방식이 바뀝니다. 기존에 Full Table Scan 방식에서 Full Index Scan 방식으로 변화하게 됩니다.
CREATE INDEX idx_department ON employee(department);
작동 방식 변화
- 테이블 전체 대신, 인덱스(idx_department)만 읽습니다. 즉, department 컬럼만 타겟팅해서 읽습니다.
- [HR, HR, IT, Sales, Sales, Sales] 을 순서대로 읽으며 이전 값과 같으면 패스, 다르면 출력합니다
인덱스 구조
인덱스는 보통 B-Tree 구조로 저장됩니다. 그래서 인덱스만 보면 이런 식으로 정렬되어 있습니다.
DISTINCT는 이걸 타고 내려가면서, "이전 값과 같은가?" 비교만 하면 되니까 훨씬 효율적이죠.
idx_department:
HR → HR → IT → Sales → Sales → Sales
4.2. GROUP BY
GROUP BY는 중복된 값을 묶어서 처리할 때 사용합니다. 집계함수와 함께 사용할 때 distinct보다 더 직관적이고 유연합니다. GROUP BY 를 사용하면 DISTINCT와 결과는 같지만, 작동 구조는 다릅니다.
SELECT department FROM employees GROUP BY department;
작동 방식
- department 컬럼만 읽음 (인덱스 사용 가능)
- 같은 값끼리 그룹핑
- HR, IT, Sales 각각 하나씩 결과로 뽑힘
DISTINCT와의 차이
- DISTINCT는 고유값을 식별해서 필터링
- GROUP BY는 고유값을 묶어서 그룹화 (집계함수도 함께 쓸 수 있음)
💬 오늘의 깨달음
쿼리 | 상황 | 장점 |
DISTINCT | 단순 중복 제거 | 간단 |
인덱스 + DISTINCT | 중복 제거 + 성능 향상 | Full Table Scan 피함 |
GROUP BY | 중복 제거 + 집계 필요할 때 | 병렬 처리 가능 |
DISTINCT와 그 대안들을 요약해보면 위의 표와 같겠네요. DISTINCT의 작동 원리를 파악했으니, 대용량 데이터를 대상으로 중복을 제거할 땐 인덱스나 GROUP BY를 상황에 맞게 골라 써봐야겠습니다!
'# 1. 언어 > # 1.1. SQL' 카테고리의 다른 글
[SQL기본] NOT IN 사용 시 주의사항 (0) | 2025.04.07 |
---|---|
[mysql] Workbench user생성하기 (0) | 2025.03.12 |
[MySQL] 데이터 모델링 (0) | 2024.01.10 |
[MySQL] JOIN 🆚 서브쿼리 (0) | 2024.01.04 |
[MySQL] 데이터베이스 & 유저 생성 (0) | 2024.01.01 |