SELECT DISTINCT를 지정하면 쿼리 결과에는 고유한 행만 남습니다. 즉, 결과에서 완전히 일치하는 행들의 각 집합마다 행 1개만 남습니다.
고유한 값을 가져야 하는 컬럼 목록을 지정할 수 있습니다: SELECT DISTINCT ON (column1, column2,...). 컬럼을 지정하지 않으면 모든 컬럼을 기준으로 판단합니다.
다음 테이블을 예로 살펴보겠습니다:
DISTINCT를 사용하는 경우:
DISTINCT 사용:
DISTINCT와 ORDER BY
ClickHouse는 하나의 쿼리에서 서로 다른 컬럼에DISTINCT 절과 ORDER BY 절을 함께 사용할 수 있습니다. DISTINCT 절은 ORDER BY 절보다 먼저 실행됩니다.
다음 테이블을 예로 살펴보겠습니다:
2, 4는 정렬 전에 잘려 나갔습니다.
쿼리를 작성할 때는 이러한 구현상의 특이사항을 고려하십시오.
NULL 처리
DISTINCT는 NULL을 NULL이 특정 값이며 NULL==NULL인 것처럼 취급합니다. 즉, DISTINCT 결과에서는 NULL을 포함한 서로 다른 조합도 한 번만 나타납니다. 이는 대부분의 다른 문맥에서의 NULL 처리 방식과 다릅니다.
대안
집계 함수를 사용하지 않고SELECT 절에 지정된 것과 동일한 값 집합에 GROUP BY를 적용해도 동일한 결과를 얻을 수 있습니다. 다만 GROUP BY 방식과 비교하면 몇 가지 차이점이 있습니다.
DISTINCT는GROUP BY와 함께 사용할 수 있습니다.- 외부 실행이 시작되기 전이라면, ORDER BY가 없는 쿼리는 LIMIT를 충족할 만큼 서로 다른 행을 읽는 즉시 중지될 수 있습니다.
- 외부 실행이 시작되기 전이고
ORDER BY가 생략된 경우,ALL없이 지정한LIMIT ... AFTER ... UNTIL범위 역시 범위가 끝나면 쿼리를 중지시킬 수 있습니다. - 데이터 블록은 외부 실행이 시작되기 전까지 처리되는 대로 출력됩니다.
외부 메모리를 사용하는 DISTINCT
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의 스필 임계값을 사용합니다:
LIMIT이 충족되면 쿼리가 조기에 완료될 수 있습니다.
일단 스필이 시작되면 나머지 결과를 반환하기 전에 남은 입력을 모두 읽어야 합니다.
쿼리에 ORDER BY가 포함된 경우 해당 결과는 요청된 순서대로 반환됩니다.
DISTINCT가 키의 접두사로 정렬된 입력을 사용하는 경우에는 스필이 발생하지 않습니다. 다만 동일한 접두사를 가진 행 그룹이 크면 여전히 상당한 메모리를 사용할 수 있습니다.
optimize_distinct_in_order와 마찬가지로, 스필 과정에서 이진 표현은 다르지만 비교 시 같은 값으로 판단되는 부동소수점 값이 중복 제거될 수 있습니다. 여기에는 0.0과 -0.0, 또는 페이로드가 다른 NaN 값이 포함됩니다.