정렬을 지시하지 않은 결과의 순서는 우연입니다. 어제까지 잘 나오던 순서가 오늘 바뀌어도 데이터베이스는 약속을 어긴 것이 아닙니다.
풀고 시작
문제 1. ORDER BY 절에서 사용할 수 없는 것은?
집합 연산자로 여러 질의를 묶으면 정렬은 맨 마지막에 한 번만 쓸 수 있습니다. 별칭과 컬럼 순번은 ORDER BY가 SELECT 다음에 처리되기 때문에 모두 사용할 수 있고, 결과에 표시하지 않은 컬럼으로도 정렬할 수 있습니다.
가장 마지막에 처리되는 절
1강에서 본 처리 순서의 맨 끝이 ORDER BY입니다. FROM으로 대상을 정하고, 조건으로 걸러 내고, 묶고, 열을 고른 다음에야 줄을 세웁니다. 이 위치 때문에 ORDER BY만 누리는 특권이 두 개 있습니다.
첫째, SELECT 절에서 붙인 별칭을 쓸 수 있습니다. 별칭은 SELECT에서 생기는데 ORDER BY는 그다음이니 이미 알고 있죠. 둘째, SELECT 절에 나열한 순서를 숫자로 가리킬 수 있습니다. 두 번째 컬럼으로 정렬하라는 지시를 숫자 2로 쓸 수 있습니다. 다만 이 방식은 SELECT 절의 컬럼 순서를 바꾸면 정렬 기준이 조용히 따라 바뀌므로, 읽기와 유지보수 면에서는 컬럼명이나 별칭을 쓰는 편이 낫습니다.
정렬 방향은 오름차순이 기본값입니다. 아무것도 쓰지 않으면 작은 값부터 나오고, 큰 값부터 원하면 내림차순을 지정합니다. 여러 컬럼을 나열하면 앞의 컬럼이 같을 때만 뒤의 컬럼이 작동하고, 방향은 컬럼마다 따로 지정할 수 있습니다.
NULL은 어디에 서는가
정렬에서 값이 없는 행이 어디로 가는지는 제품마다 다릅니다. 어떤 제품은 오름차순에서 NULL을 가장 뒤에 두고, 어떤 제품은 가장 앞에 둡니다. 그래서 표준 SQL에는 NULL의 위치를 직접 지정하는 구문이 있고, 대부분의 제품이 이를 지원합니다. NULLS FIRST와 NULLS LAST가 그것입니다.
시험에서는 특정 제품의 기본 동작을 외우게 하기보다 기본 동작이 제품에 따라 갈린다는 사실과 위치를 명시할 수 있다는 사실을 확인합니다. 실무에서는 명시해 두는 편이 안전합니다. 데이터베이스를 옮기는 순간 보고서의 첫 줄이 마지막 줄로 내려앉는 일을 겪지 않으려면요.
정렬 대상은 결과에 없어도 됩니다
ORDER BY의 재밌는 성질 하나는 결과에 표시하지 않는 컬럼으로도 정렬할 수 있다는 점입니다. 사원명만 뽑으면서 입사일 순으로 줄을 세워도 됩니다. 입사일은 화면에 나오지 않지만 순서에는 반영되죠.
여기에 예외가 있습니다. DISTINCT를 쓰거나 집합 연산자로 묶은 경우에는 결과에 없는 컬럼으로 정렬할 수 없습니다. DISTINCT는 중복을 없애면서 원래 행의 정체를 지워 버리기 때문입니다. 같은 이름이 두 번 있었는데 하나로 합쳤다면, 그 하나의 입사일이 무엇이어야 할지 정할 수 없습니다.
GROUP BY를 쓴 경우에도 마찬가지로 그룹 기준 컬럼과 집계 함수 결과로만 정렬할 수 있습니다. 4강에서 SELECT 절에 걸렸던 규칙이 ORDER BY에도 그대로 적용되는 셈이죠.
정렬은 값이 비싼 작업입니다
정렬은 데이터를 모두 모아 놓고 순서를 매기는 작업이라 메모리와 시간을 씁니다. 정렬할 양이 메모리에 담기지 않으면 디스크를 쓰게 되고 그때부터 눈에 띄게 느려집니다.
그래서 실무의 요령이 몇 가지 있습니다. 정렬 기준 컬럼에 인덱스가 있으면 데이터베이스가 인덱스를 순서대로 읽어 정렬 작업 자체를 건너뛸 수 있습니다. 정렬한 결과의 앞부분만 필요하다면 12강에서 볼 Top N 구문으로 범위를 줄여 주는 편이 낫습니다. 그리고 화면에 필요하지 않은 정렬은 아예 빼는 것이 가장 확실한 개선입니다. 목록 화면마다 습관적으로 붙은 정렬 하나가 전체 응답 시간의 절반을 먹고 있는 경우가 드물지 않습니다.
한 가지 더, 문자로 저장된 숫자를 정렬하면 사전 순으로 정렬됩니다. 10이 2보다 앞에 오죠. 자료형이 문자인데 숫자처럼 보이는 컬럼을 정렬할 때는 숫자로 변환해 정렬해야 하고, 그 변환 때문에 인덱스를 못 쓰게 되는 대가를 함께 치릅니다. 애초에 숫자로 저장했어야 하는 값이라는 신호이기도 합니다.
다음 강부터 조인으로 들어갑니다. 2과목의 문항 수가 가장 몰려 있는 구간이니 천천히 보셔도 좋습니다.
인출 문제
문제 1. ORDER BY 절이 SELECT 절의 별칭을 사용할 수 있는 이유는?
처리 순서에서 SELECT 다음에 오는 절만 별칭을 알아볼 수 있고, 그 절은 ORDER BY입니다. WHERE와 GROUP BY와 HAVING은 모두 SELECT보다 먼저 처리되므로 별칭을 인식하지 못합니다.
문제 2. 정렬에서 값이 없는 행의 위치에 대한 설명으로 옳은 것은?
기본 동작이 제품마다 갈리기 때문에 NULLS FIRST나 NULLS LAST로 명시하는 구문이 있습니다. 값이 없는 행이 결과에서 빠지는 것은 아닙니다.
문제 3. DISTINCT를 사용한 SELECT 문에서 결과에 표시하지 않은 컬럼으로 정렬할 수 없는 이유는?
중복 제거로 여러 행이 하나로 합쳐지면 그 행이 원래 어느 행이었는지가 사라집니다. 그래서 결과에 남지 않은 컬럼의 값이 무엇이어야 할지 결정할 수 없습니다.
문제 4. 여러 컬럼을 ORDER BY에 나열했을 때의 동작으로 옳은 것은?
앞에서부터 우선하며, 앞이 같을 때만 뒤가 작동합니다. 정렬 방향은 컬럼마다 따로 지정할 수 있어 하나는 오름차순, 하나는 내림차순으로 섞어 쓸 수 있습니다.
더 풀기
출제기준의 세세항목을 따라 이 강의 범위에서 새로 낸 문제입니다. 모의고사도 여기에서 뽑습니다.
묶음 1
문제 1. ORDER BY 절이 논리적 처리 순서에서 가장 마지막인 이유로 가장 알맞은 것은?
정렬은 결과 집합을 만든 다음에 하는 일입니다. 그래서 SELECT 절의 별칭도 쓸 수 있습니다.
문제 2. ORDER BY 절에서 SELECT 절의 별칭을 쓸 수 있는 이유는?
처리 순서로 설명됩니다. 반대로 WHERE는 SELECT보다 먼저 처리되어 별칭을 쓸 수 없습니다.
문제 3. ORDER BY의 기본 정렬 방향은?
방향을 적지 않으면 오름차순입니다. 내림차순은 DESC를 명시해야 합니다.
문제 4. 정렬 기준을 여러 개 지정했을 때의 동작으로 옳은 것은?
앞의 기준이 우선이고 동점일 때 뒤의 기준이 순서를 정합니다. 이것을 알아야 예상한 순서를 얻을 수 있습니다.