데이터베이스에서 데이터 통계를 낼 때 집계 함수인 COUNT()와 SUM()은 가장 기본적이고 널리 사용되는 SQL 함수입니다. 하지만 두 함수를 사용하면서 COUNT(*)는 정상 작동하지만 SUM(*)을 수행하려 할 때는 SQL 문법 에러(Syntax Error)를 맞닥뜨리게 됩니다. 이번 포스팅에서는 왜 이런 현상이 발생하는지, 그리고 COUNT(*)와 COUNT(컬럼명)의 Null 처리 및 성능 차이에 대해 상세히 다뤄보겠습니다.
1. SUM(*)은 왜 불가능할까? (집계 대상의 데이터 타입)
결론부터 말하면, SUM() 함수는 숫자형 데이터의 산술 합계를 계산하는 연산이고, COUNT() 함수는 단순히 행(Row)의 개수를 세는 연산이기 때문에 발생하는 차이입니다.
SUM(*)이 문법 오류인 이유: 와일드카드 기호인*(Asterisk)는 테이블 내의 모든 컬럼(All Columns)을 의미합니다. 만약SUM(*)을 허용하게 되면, 해당 행에 포함된 숫자형 컬럼뿐만 아니라 문자열(VARCHAR), 날짜(DATE), 논리형(BOOLEAN) 등 데이터베이스가 산술 덧셈을 수행할 수 없는 다양한 타입의 모든 데이터를 전부 더하라는 의미가 됩니다. 이는 수학적으로 연산이 불가능하므로, DBMS(MySQL, Oracle 등) SQL 파서 단에서 아예 에러를 내뿜으며 실행을 차단하는 것입니다.SUM(컬럼명)만 가능한 이유: 그렇기 때문에SUM()함수는 무조건 덧셈 계산이 가능한 특정 컬럼 한 개를 콕 집어서 지정해 주어야 합니다. 이때 지정된 컬럼에 문자열 값이 들어있으면 무조건 에러가 발생하거나 DBMS 내부의 암묵적 캐스팅 규칙에 의해0으로 처리될 수 있습니다.
2. COUNT(*) vs COUNT(컬럼명)
반면, 개수를 세는 COUNT() 함수는 모든 컬럼을 대상으로 하는 COUNT(*)와 특정 컬럼을 지정하는 COUNT(컬럼명) 두 가지 문법을 모두 정상 지원합니다. 하지만 이 둘 사이에는 Null 처리 규칙과 동작 메커니즘에서 큰 차이가 있습니다.
1) Null값 처리 여부 (가장 중요한 차이)
COUNT(*): 테이블의 전체 행 개수를 반환합니다. 특정 컬럼에 Null값이 들어있거나, 혹은 행의 모든 값이 Null이라 할지라도 행의 존재 자체를 카운트하므로 Null 여부와 상관없이 무조건 셉니다.COUNT(컬럼명): 지정된 컬럼의 값이 Null이 아닌(Not Null) 행의 개수만 카운트합니다.- 예: 5개의 행이 있는 테이블에서
age컬럼 중 2개가 Null이라면,COUNT(*)는5를 반환하고COUNT(age)는3을 반환합니다.
- 예: 5개의 행이 있는 테이블에서
2) 성능과 옵티마이저의 동작
과거 데이터베이스(Legacy DBMS)에서는 COUNT(*)를 사용하면 모든 컬럼을 메모리로 퍼 올려야 하므로 COUNT(1)이나 COUNT(PK컬럼)을 쓰는 것이 더 빠르다는 속설이 있었습니다.
하지만 최신 DBMS(특히 MySQL InnoDB 엔진) 환경에서는 성능 차이가 없거나 오히려 COUNT(*)가 더 나은 최적화를 보입니다.
- MySQL
COUNT(*)최적화: MySQL InnoDB 엔진의 옵티마이저는COUNT(*)쿼리가 들어오면 레코드가 가장 작은 세컨더리 인덱스(Secondary Index)를 찾아 해당 인덱스의 리프 노드 개수만 고속 스캔하여 결과를 냅니다. 모든 컬럼의 데이터를 디스크에서 다 읽어오는 비효율은 발생하지 않습니다. COUNT(컬럼명): 지정된 컬럼에 Null값이 있는지 일일이 메모리에 올려 null 체크를 수행하는 CPU 연산이 수반되므로, 해당 컬럼에 Not Null 제약 조건이 걸려있지 않다면 미세하게 더 느릴 수 있습니다.
Summary
SUM(*): 연산 불가. 덧셈은 숫자 타입 컬럼 한 개만 명시적으로 연산해야 하므로 허용되지 않습니다.COUNT(*): 테이블 전체 행 개수 파악용. Null값도 포함하며 옵티마이저 최적화가 잘 되어 있으므로 기본 개수 조회 시 적극 권장됩니다.COUNT(컬럼명): 해당 컬럼이 Null이 아닌 유효 행 개수만 측정하므로 비즈니스 로직 필요에 따라 선택적으로 사용합니다.
SQL 집계 함수의 이러한 데이터 타입 및 Null 판단 규칙의 세세한 메커니즘을 명확히 알아두어야 데이터 정합성을 깨뜨리지 않는 쿼리를 구현할 수 있습니다.