로컬 MariaDB에서 잘 돌던 GROUP BY 쿼리가 다른 서버에서 1055로 막힌 이유
문제 발생
작성자별 최신 글을 뽑는 쿼리가 로컬에서는 잘 돌았습니다.
SELECT author_id, title, MAX(created_at)
FROM dev_posts
GROUP BY author_id;다른 서버에 올리자 바로 실패했습니다.
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause
and contains nonaggregated column 'meokko.dev_posts.title' which is not
functionally dependent on columns in GROUP BY clause; this is incompatible
with sql_mode=only_full_group_by원인 분석
환경 차이가 아니라 원래 잘못된 쿼리였습니다. MySQL 문서는 ONLY_FULL_GROUP_BY가 켜져 있으면 select 목록·HAVING·ORDER BY가 GROUP BY에 없고 그에 함수 종속도 아닌 비집계 컬럼을 참조하는 쿼리를 거부한다고 설명합니다. 그리고 이 모드는 MySQL에서 기본으로 켜져 있습니다.
MariaDB는 다릅니다. MariaDB 문서의 기본 sql_mode는 STRICT_TRANS_TABLES, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, NO_ENGINE_SUBSTITUTION이고 ONLY_FULL_GROUP_BY는 포함되어 있지 않습니다. MariaDB 문서도 이 모드를 "GROUP BY에 없고 집계 함수에 넘겨지지도 않은 컬럼의 SELECT를 금지하며 1055 오류를 낸다"고 같은 의미로 적습니다.
그래서 로컬에서는 오류가 아니라 더 나쁜 일이 벌어지고 있었습니다. title은 그룹 안 여러 행 중 아무 것이나 골라져서, MAX(created_at)이 가리키는 글의 제목이라는 보장이 전혀 없었습니다. 오류가 났을 때 잘못이 드러난 게 오히려 다행인 경우입니다.
함수 종속이면 예외입니다. 문서는 비집계 컬럼이 GROUP BY 컬럼의 기본 키이거나 unique NOT NULL 컬럼이면 종속으로 인정한다고 설명합니다.
해결 방안
- "그룹당 한 행"이 목적이면 윈도 함수로 씁니다. GROUP BY로 흉내내지 않습니다.
SELECT author_id, title, created_at
FROM (
SELECT author_id, title, created_at,
ROW_NUMBER() OVER (PARTITION BY author_id ORDER BY created_at DESC) AS rn
FROM dev_posts
) ranked
WHERE rn = 1;-
진짜로 아무 값이나 괜찮다면 그 의도를 코드에 적습니다. 문서가 이 용도로
ANY_VALUE()를 안내합니다 — 어떤 값이 와도 상관없다는 사실이 쿼리에 남습니다. -
집계할 것은 집계 함수로 감쌉니다.
COUNT,MAX,GROUP_CONCAT중 실제로 원하는 것을 고릅니다. -
서버 변수를 맞추는 것으로 때우지 않습니다. 로컬
sql_mode에ONLY_FULL_GROUP_BY를 추가해 같은 오류를 미리 보는 건 좋지만, 반대로 운영에서 모드를 끄는 건 틀린 결과를 조용히 되돌리는 선택입니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.