GROUP BY [expr](, expr...) 쿼리는 SELECT 문의 질의 결과를 expr을 기준으로 묶어 새로운 row들을 반환하는 역할을 한다. 이는 보통 집계 함수와 함께 쓰이는데, 예를 들면 아래와 같다.

tbl_2nd_grade라는 테이블이 2학년 학생들의 정보를 관리하고, 여기에는 '반''키', '몸무게'가 각각 class, height, weight라는 이름의 컬럼에 들어가 있다고 가정한다. 위 쿼리는 GROUP BY class로 인해 row들이 class를 기준으로 묶여 class마다 '반별 학생들의 키와 몸무게 평균'을 결과로 반환하게 된다. GROUP BY 없이 어플리케이션 레벨에서 이러한 요구사항을 만족시키려면, class를 key로 갖는 dictionary에 학생 수와 함께 키, 몸무게를 누적시킨 후 평균을 계산하는 로직을 작성해야할 것이다.

GROUP BY가 포함된 SELECT 문은 그룹마다 하나의 행을 반환한다. 예를 들어 class가 1, 2, 3만 있다면 3개의 행이 반환될 것이고, 1부터 10까지 있다면 10개의 행이 반환된다. GROUP BY가 포함된 쿼리를 작성할 때 인지하면 좋은 것은, GROUP BY 절에 명시한 expression이 아니라면 SELECT 절에 metric을 명시할 때 집계 함수 등을 통해 row가 하나만 등장하도록 만들어야 한다는 것이다. 예를 들면,

위의 예제는 유효한 쿼리지만, 아래의 예제는 유효하지 않다. grade를 기준으로 GROUP BY 되었기에 height와 weight는 AVG 함수에 전달되어 알아서 집계되어 group마다 하나의 값만을 가질텐데, student_number는 group에 따라 여러 개의 값을 가질 수 있기 때문이다. 논리적으로 맞지 않는 것이다.

GROUP BY 써먹기

사실 웬만하면 GROUP BY는 유용하다. 내 경우에는 수만~수십만 row가 넘는 데이터를 특별한 기준으로 나누어 집계하는 쿼리를 최적화할 때 GROUP BY의 유용함을 느낄 수 있었다. 내가 처했던 상황을 조금 간단한 예로 표현한다면, 10만 개가 넘는 학생별 시험 성적 데이터가 row마다 학번, 수학 점수, 과학 점수, ... 형태로 이루어져 있다고 칠 때, 과목별로 5점 단위마다 학생 수를 count해야 하는 일이었다. '수학 0~4점에 몇명, 5~9점에 몇명, ..., 95~99점에 몇명, 100점에 몇명' 하는 식의 데이터를 만들어야 하는 것이다. 처음 했던 것은, 과목을 기준으로 GROUP BY하고 score에 대해 CASE WHEN을 사용하는 것이었다.

결과는 적당히 잘 나오지만, 쿼리 시간은 SELECT절에 포함시키는 metric의 수에 비례하여 늘어난다는 것을 생각하면 확실히 좋기만 한 쿼리는 아니다. 만점이 더 높다면 그만큼 쿼리 시간이 더 늘어날 것이고, 피겨 스케이팅처럼 만점이 따로 없는 경우를 생각한다면 그렇게 유연한 쿼리도 아니다. GROUP BY에 단지 column name이 아니라 expression을 사용할 수 있다는 것을 응용하면 더 나은 쿼리를 작성할 수 있다.

subject와 score를 5로 나눠 소수점을 버리는 floor(score / 5)를 기준으로 group이 만들어질테니, 수학 0~4점은 math, 0, 13, 수학 5~9점은 math, 1, 3, ..., 수학 100점은 math, 100, 17 이런 식으로 각 row가 구성될 것이다. 이러한 쿼리가 빠른 이유는, row들을 iteration하는 for문 안에 수많은 if 절이 있는 것dictionary에 값을 누적하는 것 중 무엇이 빠른지를 생각하면 된다.

추가적으로, GROUP BY는 결과를 '분산'시키는 것에도 유용하다. 예를 들어 SELECT AVG(score) FROM tbl_score_2018_02_mid;모든 학생의 전체 과목에 대한 평균 점수를 집계할 수 있을텐데, 이걸 학생 단위로 결과를 분산시키기 위해 SELECT AVG(score) FROM tbl_score_2018_02_mid GROUP BY student_number;처럼 표현할수도 있다는 것이다.

'데이터베이스 > SQL' 카테고리의 다른 글

Literal SELECT  (0) 2019.02.12
집계 함수와 조건식을 함께 사용하기(SELECT FROM SELECT)  (0) 2019.02.12

+ Recent posts