SELECT DISTINCT
SELECT DISTINCT
SELECT DISTINCT가 지정되면 쿼리 결과에 고유한 행만 남아요. 따라서 결과에서 완전히 일치하는 행 집합 중 단일 행만 남습니다.
컬럼 목록을 지정할 수 있어요: SELECT DISTINCT ON (column1, column2,...). 컬럼이 지정되지 않으면 모두 고려됩니다.
출처: 문서
본문
다음 테이블을 고려해 보세요:
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 2 │ 2 │ 2 │
│ 1 │ 1 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
컬럼을 지정하지 않고 DISTINCT 사용:
SELECT DISTINCT * FROM t1;
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 1 │ 1 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
지정된 컬럼으로 DISTINCT 사용:
SELECT DISTINCT ON (a,b) * FROM t1;
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
DISTINCT and ORDER BY
ClickHouse는 한 쿼리에서 서로 다른 컬럼에 DISTINCT와 ORDER BY 절을 사용하는 것을 지원합니다. DISTINCT 절은 ORDER BY 절보다 먼저 실행됩니다.
다음 테이블을 고려해 보세요:
┌─a─┬─b─┐
│ 2 │ 1 │
│ 1 │ 2 │
│ 3 │ 3 │
│ 2 │ 4 │
└───┴───┘
데이터 선택:
SELECT DISTINCT a FROM t1 ORDER BY b ASC;
┌─a─┐
│ 2 │
│ 1 │
│ 3 │
└───┘
다른 정렬 방향으로 데이터 선택:
SELECT DISTINCT a FROM t1 ORDER BY b DESC;
┌─a─┐
│ 3 │
│ 1 │
│ 2 │
└───┘
행 2, 4는 정렬 전에 잘렸습니다.
쿼리를 프로그래밍할 때 이 구현 특이성을 고려하세요.
Null Processing
DISTINCT는 NULL을 특정 값인 것처럼, 그리고 NULL==NULL인 것처럼 처리합니다. 즉, DISTINCT 결과에서 NULL이 있는 다른 조합은 한 번만 발생합니다. 이것은 대부분의 다른 컨텍스트의 NULL 처리와 다릅니다.
Alternatives
SELECT 절로 지정된 같은 값 집합에 GROUP BY를 집계 함수 없이 적용해 같은 결과를 얻을 수 있습니다. 그러나 GROUP BY 접근 방식과 몇 가지 차이가 있습니다:
DISTINCT는GROUP BY와 함께 적용될 수 있어요.- 외부 실행이 시작되기 전에 ORDER BY가 없는 쿼리는 LIMIT을 충족할 만큼 충분히 많은 다른 행을 읽자마자 중지될 수 있어요.
- 외부 실행이 시작되기 전이고
ORDER BY가 생략되었을 때,ALL이 없는LIMIT ... AFTER ... UNTIL범위도 범위가 끝나면 쿼리를 중지할 수 있습니다. - 외부 실행이 시작될 때까지 데이터 블록은 처리된 대로 출력됩니다.
DISTINCT in External Memory
DISTINCT는 메모리에 보관하기 너무 큰 고유 값 집합을 처리하기 위해 임시 데이터를 디스크에 쓸 수 있어요. 이는 추가 디스크 I/O가 필요하고 쿼리를 더 느리게 만들 수 있습니다.
두 설정이 스필이 시작되는 시점을 제어합니다:
max_bytes_before_external_distinct는 총 쿼리 메모리의 바이트 단위 임계값을 설정합니다. 기본값은0(비활성화)입니다.max_bytes_ratio_before_external_distinct는 서버 또는 사용자 제한 아래 사용 가능한 메모리의 분율을 설정하며, 실행 시작 시 측정됩니다. 기본값은0.5이며 어느 제한도 적용되지 않으면 효과가 없습니다.
두 임계값이 모두 적용되면 더 작은 것이 사용됩니다. 스필을 비활성화하려면 두 설정을 0으로 설정하세요.
max_memory_usage는 비율에 영향을 주지 않습니다. 쿼리 메모리 제한에 상대적으로 스필을 구성하려면 그 제한 아래에 절대 임계값을 설정하세요. 예를 들어, 이 쿼리는 256 MiB 쿼리 메모리 제한과 함께 16 MiB 스필 임계값을 사용합니다:
SELECT DISTINCT number % 1000000 AS id
FROM numbers(2000000)
SETTINGS
max_bytes_before_external_distinct = 16777216,
max_bytes_ratio_before_external_distinct = 0,
max_memory_usage = 268435456;
이 임계값은 메모리 사용을 제한하지 않습니다. 다른 쿼리 처리와 스필 자체를 위한 공간을 남겨 두세요. 스필은 메모리 압박 시 더 일찍 시작될 수도 있습니다.
행은 스필 전에 반환될 수 있고, 이 단계에서 충족된 LIMIT는 쿼리를 일찍 끝낼 수 있습니다. 스필이 시작되면 나머지 결과가 반환되기 전에 나머지 입력을 읽어야 합니다. 쿼리가 ORDER BY를 포함하면 그 결과가 요청된 순서로 반환됩니다.
DISTINCT가 키의 접두사로 정렬된 입력을 사용하면 스필하지 않습니다. 같은 접두사를 가진 큰 행 그룹도 여전히 상당한 메모리를 사용할 수 있습니다.
optimize_distinct_in_order와 마찬가지로, 스필은 이진 표현은 다르지만 비교가 같은 부동 소수점 값을 중복 제거할 수 있습니다. 여기에는 0.0과 -0.0, 또는 페이로드가 다른 NaN 값이 포함됩니다.