24.3부터 새 쿼리 분석기가 기본적으로 활성화되었습니다.
작동 방식에 대한 자세한 내용은 여기에서 확인할 수 있습니다.
알려진 비호환성
잘못된 쿼리는 더 이상 최적화되지 않습니다
예시 1
toString(number)만 사용할 수 있음에도 프로젝션 목록에서 컬럼 number를 사용합니다.
이전 분석기에서는 GROUP BY toString(number)가 GROUP BY number,로 최적화되어 해당 쿼리가 유효했습니다.
예시 2
number 컬럼은 다른 키로 집계한 뒤에 사용됩니다.
이전 쿼리 분석기는 number > 5 필터를 HAVING 절에서 WHERE 절로 옮겨 이 쿼리를 수정했습니다.
WHERE 절로 옮겨야 합니다:
잘못된 쿼리로 CREATE VIEW
SELECT 쿼리로 VIEW를 생성할 수 있었습니다.
이 경우 첫 번째 SELECT 또는 INSERT 시점에 실패했습니다(MATERIALIZED VIEW의 경우).
이제는 이런 방식으로 VIEW를 생성할 수 없습니다.
예시
JOIN 절의 알려진 비호환 사항
프로젝션의 컬럼을 사용한 JOIN
SELECT 목록의 별칭은 JOIN USING 키로 사용할 수 없습니다.
새로운 설정인 analyzer_compatibility_join_using_top_level_identifier을 활성화하면 JOIN USING의 동작이 바뀌며, 왼쪽 테이블의 컬럼을 직접 사용하는 대신 SELECT 쿼리의 프로젝션 목록에 있는 표현식을 기준으로 식별자를 우선 해석합니다.
예를 들면:
analyzer_compatibility_join_using_top_level_identifier를 true로 설정하면, 이전 버전의 동작과 동일하게 join 조건이 t1.a + 1 = t2.b로 해석됩니다.
결과는 2, 'two'입니다.
설정이 false이면 join 조건은 기본적으로 t1.b = t2.b로 해석되며, 쿼리는 2, 'one'을 반환합니다.
t1에 b가 없으면 쿼리는 오류를 발생시키며 실패합니다.
JOIN USING과 ALIAS/MATERIALIZED 컬럼의 동작 변경
ALIAS 또는 MATERIALIZED 컬럼이 포함된 JOIN USING 쿼리에서 *를 사용하면, 기본적으로 해당 컬럼도 결과 집합에 포함됩니다.
예시:
id와 함께 payload 컬럼도 포함됩니다.
반면 이전 분석기에서는 특정 설정(asterisk_include_alias_columns 또는 asterisk_include_materialized_columns)이 활성화된 경우에만 이러한 ALIAS 컬럼이 포함되었으며,
컬럼 순서도 달라질 수 있었습니다.
일관되고 예상 가능한 결과를 얻으려면, 특히 기존 쿼리를 분석기로 마이그레이션할 때는 *를 사용하는 대신 SELECT 절에서 컬럼을 명시적으로 지정하는 것이 좋습니다.
USING 절의 컬럼 타입 수정자 처리
USING 절에 지정된 컬럼의 공통 상위 타입(common supertype)을 결정하는 규칙이 표준화되어, 더 예측 가능한 결과를 얻을 수 있습니다.
특히 LowCardinality 및 Nullable 같은 타입 수정자를 다룰 때 그렇습니다.
LowCardinality(T)andT: 타입이LowCardinality(T)인 컬럼을 타입이T인 컬럼과 조인하면, 결과 공통 상위 타입은T가 되며LowCardinality수정자는 사실상 제거됩니다.Nullable(T)andT: 타입이Nullable(T)인 컬럼을 타입이T인 컬럼과 조인하면, 결과 공통 상위 타입은Nullable(T)가 되어 널 허용 속성이 유지됩니다.
id의 공통 상위 유형(common supertype)이 String으로 결정되고, t1의 LowCardinality 수정자는 제거됩니다.
프로젝션 컬럼 이름 변경 사항
호환되지 않는 함수 인수 타입
if 함수의 인수는 항상 공통 supertype을 가져야 합니다.
예를 들어, 다음 쿼리는 There is no supertype for types Array(UInt8), String because some of them are Array and some of them are not라는 오류와 함께 실패합니다:
이기종 클러스터
enable_analyzer 설정값이 서로 다른 서버 간에는 분산 쿼리를 실행할 수 없습니다.
뮤테이션은 이전 분석기로 해석됩니다
QUALIFY 절은 사용할 수 없습니다.
현재 상태는 여기에서 확인할 수 있습니다.
지원되지 않는 기능
- Annoy 인덱스.
- Hypothesis 인덱스. 여기에서 작업이 진행 중입니다.
- Window view는 지원되지 않습니다. 앞으로도 지원할 계획이 없습니다.
Cloud 마이그레이션
마이그레이션 워크플로
normalized_query_hash를 사용해system.query_log를 필터링하여 쿼리를 식별합니다:
- 다음 설정을 추가해 분석기를 활성화한 뒤 쿼리를 실행합니다.
- 분석기를 비활성화했을 때의 출력과 일치하는지 확인할 수 있도록 쿼리를 리팩터링하고 결과를 검증합니다.
알 수 없는 표현식 식별자
Unknown expression identifier ... in scope ... (UNKNOWN_IDENTIFIER). 예외 코드: 47
원인: 필터에서 계산된 별칭(alias)을 참조하거나, 모호한 서브쿼리 프로젝션, 또는 “동적” CTE 범위와 같은 비표준적이고 관대한 레거시 동작에 의존하는 쿼리는 이제 유효하지 않은 것으로 올바르게 판단되어 즉시 거부됩니다.
해결 방법: SQL 패턴을 다음과 같이 수정하십시오.
- 필터 로직: 결과를 기준으로 필터링하는 경우 WHERE의 로직을 HAVING으로 옮기고, 원본 데이터를 기준으로 필터링하는 경우 WHERE에 동일한 표현식을 다시 작성하십시오.
- 서브쿼리 범위: 바깥쪽 쿼리에 필요한 모든 컬럼을 명시적으로 선택하십시오.
- JOIN 키: 키가 별칭(alias)인 경우 USING 대신 전체 표현식을 포함한 ON을 사용하십시오.
- 바깥쪽 쿼리에서는 내부 테이블이 아니라 서브쿼리/CTE 자체의 별칭(alias)을 참조하십시오.
GROUP BY의 비집계 컬럼
Column ... is not under aggregate function and not in GROUP BY keys (NOT_AN_AGGREGATE). 예외 코드: 215
원인: 이전 분석기는 GROUP BY 절에 없는 컬럼도 선택할 수 있게 허용했습니다(이 경우 임의의 값을 선택하는 일이 많았습니다). 분석기는 표준 SQL을 따릅니다. 즉, 선택한 모든 컬럼은 집계 함수이거나 그룹화 키여야 합니다.
해결 방법: 해당 컬럼을 any(), argMax()로 감싸거나 GROUP BY에 추가합니다.
중복된 CTE 이름
CTE with name ... already exists (MULTIPLE_EXPRESSIONS_FOR_ALIAS). 예외 코드: 179
원인: 이전 분석기에서는 동일한 이름의 공통 테이블 표현식(WITH …)을 여러 개 정의해, 나중에 정의한 표현식이 앞서 정의한 표현식을 가리도록 허용했습니다. 분석기는 이러한 모호성을 허용하지 않습니다.
해결 방법: 중복된 CTE 이름을 각각 고유하게 변경합니다.
모호한 컬럼 식별자
JOIN [JOIN TYPE] ambiguous identifier ... (AMBIGUOUS_IDENTIFIER) 예외 코드: 207
원인: 쿼리에서 JOIN에 포함된 여러 테이블에 있는 동일한 컬럼 이름을, 어느 테이블의 컬럼인지 지정하지 않은 채 참조합니다. 이전 분석기는 내부 로직을 기준으로 해당 컬럼을 추정하는 경우가 많았지만, 현재 분석기는 컬럼 이름을 명시적으로 지정해야 합니다.
해결 방법: 컬럼을 table_alias.column_name 형식으로 완전히 지정하십시오.
FINAL의 잘못된 사용
Table expression modifiers FINAL are not supported for subquery... 또는 Storage ... doesn't support FINAL (UNSUPPORTED_METHOD). 예외 코드: 1, 181
원인: FINAL은 테이블 스토리지, 구체적으로 [Shared]ReplacingMergeTree에 사용하는 수정자입니다. 분석기는 다음과 같은 경우 FINAL 적용을 허용하지 않습니다.
- 서브쿼리 또는 파생 테이블(예: FROM (SELECT …) FINAL)
- FINAL을 지원하지 않는 테이블 엔진(예: SharedMergeTree)
countDistinct() 함수의 대소문자 구분
Function with name countdistinct does not exist (UNKNOWN_FUNCTION). 예외 코드: 46
원인: 함수 이름은 대소문자를 구분하며, 분석기에서 엄격하게 매핑됩니다. countdistinct(모두 소문자)는 더 이상 자동으로 인식되지 않습니다.
해결 방법: 표준 countDistinct(camelCase) 또는 ClickHouse 전용 uniq를 사용하십시오.