데이터로그😎

[SQL기본] DISTINCT, 제대로 알고 쓰자! 본문

# 1. 언어/# 1.1. SQL

[SQL기본] DISTINCT, 제대로 알고 쓰자!

지지킴 2025. 4. 10. 15:05

🧠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의 속도가 느려집니다. 

 

작동 과정

  1. employees 테이블의 모든 row+column을 읽습니다.(Full Table Scan)
    • id도 읽고, department도 읽고, 필요 없는 컬럼도 모두 읽습니다.
  2. 중복 여부 판단을 위해 정렬 또는 해시 연산 수행
    • 정렬: [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);

 

작동 방식 변화

  1. 테이블 전체 대신, 인덱스(idx_department)만 읽습니다. 즉, department 컬럼만 타겟팅해서 읽습니다.
  2.  [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;

 

작동 방식

  1. department 컬럼만 읽음 (인덱스 사용 가능)
  2. 같은 값끼리 그룹핑
  3. HR, IT, Sales 각각 하나씩 결과로 뽑힘

DISTINCT와의 차이

  • DISTINCT는 고유값을 식별해서 필터링
  • GROUP BY는 고유값을 묶어서 그룹화 (집계함수도 함께 쓸 수 있음)

💬 오늘의 깨달음

쿼리 상황 장점
DISTINCT 단순 중복 제거 간단
인덱스 + DISTINCT 중복 제거 + 성능 향상 Full Table Scan 피함
GROUP BY 중복 제거 + 집계 필요할 때 병렬 처리 가능

 

DISTINCT와 그 대안들을 요약해보면 위의 표와 같겠네요. DISTINCT의 작동 원리를 파악했으니, 대용량 데이터를 대상으로 중복을 제거할 땐 인덱스나 GROUP BY를 상황에 맞게 골라 써봐야겠습니다!