
1. 모든 데이터 추출의 시작점: SELECT, FROM, WHERE
1화에서 우리는 엑셀의 구조적 한계를 이해하고 왜 기업형 대용량 데이터 환경에서 SQL을 활용해야 하는지 그 필연성을 살펴보았습니다. 이제 본격적으로 데이터베이스 시스템 내부의 테이블에 접근하여 내가 원하는 데이터를 골라내는 가장 기본적이면서도 핵심적인 명령어 트리오인 SELECT, FROM, WHERE에 대해 알아보겠습니다.
SQL을 처음 접하는 입문자 관점에서 이 세 가지 키워드는 마치 한 문장의 영어 대화와 유사합니다. “어떤 테이블(FROM)에서, 이러한 조건(WHERE)에 맞는 데이터들만 골라, 특정한 칼럼(SELECT)들로 보여줘”라고 데이터베이스에 명령을 내리는 것입니다.
2. 현업 비즈니스 사례와 기본 쿼리 구조
이해를 돕기 위해 실제 대형 카드사나 이커머스 기업의 마케팅/데이터 분석 부서에서 자주 발생하는 실무 시나리오를 바탕으로 기본 문법을 적용해 보겠습니다.
[실무 사례 예시: 마케팅 팀의 특정 타겟 추출 요청]
온라인 쇼핑몰을 운영하는 기업의 데이터 분석가 최 선임은 마케팅 팀으로부터 다음과 같은 데이터 추출 요청을 받았습니다.
- 요청 내용: “현재 유효한 전체 회원 정보 테이블에서, 거주지가 ‘서울’이면서 가입 상태가 ‘정상’인 고객의 회원번호, 이름, 이메일 주소를 뽑아주세요.”
이 경우 최 선임이 작성하게 되는 가장 표준적인 기초 SQL 문형은 다음과 같이 구성될 수 있습니다.
SELECT
CUST_NO -- 회원번호
, CUST_NM -- 회원명
, EMAIL_ADDR -- 이메일주소
FROM
DW_MART.CUSTOMER_BASE -- 고객기본 마트 테이블
WHERE
AREA_CODE = 'SEOUL' -- 거주지역코드
AND CUST_STATUS_CD = '01'; -- 고객상태코드 (01: 정상)
위 쿼리문의 구조와 각 키워드가 담당하는 데이터베이스 내부의 작동 원리를 객관적으로 분석해 보겠습니다.
1) FROM 절: 데이터의 원천 지정
FROM 뒤에는 조회의 대상이 되는 테이블이나 뷰(View)의 이름을 명시합니다. 위의 예시에서는 DW_MART라는 스키마(데이터베이스 공간) 내에 존재하는 CUSTOMER_BASE라는 테이블을 소스로 지정했습니다. 데이터베이스 엔진은 이 명령어를 읽는 순간 해당 테이블이 저장된 물리적 디스크 공간을 탐색할 준비를 합니다.
2) WHERE 절: 행(Row) 단위 필터링
WHERE 절은 테이블 전체 데이터 중 내가 원하는 데이터만 골라내는 ‘체’의 역할을 합니다. 위 예제에서는 거주지역코드가 ‘SEOUL’이라는 조건과 고객상태코드가 ’01′(정상)이라는 두 가지 조건을 모두 만족하는 행들만 필터링하도록 지시했습니다.
대용량 데이터 환경에서 WHERE 절을 어떻게 작성하느냐에 따라 억 단위의 데이터가 수만 건으로 압축되어 서버의 연산 부담을 크게 줄이는 데 도움이 됩니다.
3) SELECT 절: 열(Column) 단위 추출
WHERE 절을 통과하여 필터링된 행들을 대상으로, 최종적으로 화면이나 결과 파일에 노출할 세로 칼럼들을 지정하는 단계입니다. 회원번호, 회원명, 이메일 주소만 명시했기 때문에 테이블 내에 존재하는 수십 개의 다른 불필요한 칼럼(예: 비밀번호, 생년월일, 주소 등)을 결과로 반환하지 않으므로 네트워크 전송량과 애플리케이션 처리 부담을 줄일 수 있습니다.
3. 대참사를 방지하는 실무 치트키: Teradata SAMPLE 구문
타 DBMS(MySQL, Oracle 등) 환경에서 SQL을 공부하고 온 직장인이나, 이제 막 실무 테이블에 접근 권한을 얻은 초보 분석가들이 가장 많이 범하는 치명적인 실수가 있습니다. 바로 테이블의 구조나 실제 적재된 데이터의 형태를 확인하기 위해 습관적으로 다음과 같은 쿼리를 실행하는 것입니다.
-- [주의] 대용량 환경에서 운영 시스템에 과도한 부하를 줄 수 있는 위험한 쿼리
SELECT * FROM DW_MART.CUSTOMER_PURCHASE_LOG;
수천만 건 혹은 수십억 건의 구매 로그가 쌓여 있는 대용량 원천 테이블에 위와 같이 조건 없는 SELECT * 문을 실행하면, 실행 계획에 따라 데이터베이스 엔진이 테이블 전체를 읽어야 할 수 있으며, 이 과정에서 많은 CPU, 메모리, 디스크 I/O 등의 시스템 자원을 소모하게 됩니다. 이는 전체 테이블을 읽는 ‘테이블 풀 스캔(Table Full Scan)’이 발생할 가능성이 높으며, 동료 분석가들의 쿼리 실행을 지연시키거나 심한 경우 데이터베이스 서버에 과도한 부하를 유발할 수 있습니다.
오라클의 경우 WHERE ROWNUM <= 10을 사용하고, MySQL은 쿼리 끝에 LIMIT 10을 붙여 조회를 제한하곤 합니다. 그렇다면 본 시리즈의 기준인 테라데이터(Teradata) 환경에서는 어떻게 대처해야 할까요? 테라데이터는 대용량 분산 환경에 특화된 고유의 강력한 문법인 SAMPLE 구문을 제공합니다.
1) Teradata SAMPLE 구문의 기본 활용법
테이블의 데이터 예시를 안전하게 10건만 확인하고 싶다면 쿼리의 가장 마지막에 SAMPLE 키워드를 배치하는 것이 효율적인 방법으로 평가받습니다.
-- 테라데이터 환경에서 안전하게 데이터 샘플 10건을 확인하는 쿼리
SELECT
CUST_NO
, PURCHASE_DT
, PURCHASE_AMT
FROM
DW_MART.CUSTOMER_PURCHASE_LOG
SAMPLE 10;
이렇게 SAMPLE 10을 선언하면 테라데이터는 분산 저장된 데이터에서 일부 행을 무작위(Random)로 추출하여 반환합니다. 사용자가 테이블의 전체 데이터를 확인하지 않고도 데이터의 형태를 빠르게 파악할 수 있어, 대용량 테이블을 탐색할 때 유용하게 활용됩니다.
2) WHERE 절과 SAMPLE 구문의 결합
단순히 테이블 전체의 샘플을 보는 것을 넘어, 특정 조건 내에서 데이터의 양상을 파악하고 싶을 때도 WHERE 절과 SAMPLE을 결합하여 요긴하게 활용할 수 있습니다.
-- 특정 조건을 만족하는 데이터 중 샘플 5건만 추출
SELECT
CUST_NO
, ITEM_CD
, PURCHASE_AMT
FROM
DW_MART.CUSTOMER_PURCHASE_LOG
WHERE
PURCHASE_AMT >= 1000000 -- 구매금액 100만 원 이상
SAMPLE 5;
위 쿼리는 구매 금액이 100만 원 이상인 고액 결제 건 중에서 시스템에 무리를 주지 않고 데이터 예시 5건만을 빠르게 포착해 줍니다. 쿼리를 본격적으로 짜기 전 데이터의 원천 값들이 어떤 형식(Format)이나 대소문자 구문으로 적재되어 있는지 검증할 때 현업 분석가들이 절대적으로 사용하는 일종의 치트키라고 볼 수 있습니다.
4. 팩트 체크 및 데이터 분석가의 관점 점검
기술적 정확성을 확보하기 위해, 실무에서 SELECT *와 SAMPLE 구문을 사용할 때 오해하기 쉬운 사실 관계들을 점검해 보겠습니다.
- SAMPLE 구문으로 추출된 데이터는 정렬된 데이터인가?
- 팩트 체크: 그렇지 않습니다.
SAMPLE 10이 반환하는 10개의 행은 데이터베이스 내부에서 정렬(Order)되거나 통계적으로 균등하게 추출된 표본이 아닙니다. SAMPLE은 임의(Random)의 행을 반환하며 실행할 때마다 결과가 달라질 수 있습니다. 따라서 통계적으로 대표성을 보장하는 표본이나 정렬된 결과로 해석해서는 안 됩니다. 만약 순서대로 정렬된 데이터를 제한하여 보고 싶다면 추후 연재될ORDER BY의 메커니즘을 적용해야 합니다.
- 팩트 체크: 그렇지 않습니다.
- SELECT * 에서 애스터리스크(*) 기호는 실무에서 권장되는가?
- 팩트 체크: 테이블의 모든 칼럼을 한 번에 불러오는
SELECT *기호는 임시 테스트 목적이 아니라면 실무 운영 쿼리나 시스템 자동화 스크립트에서는 지양하는 것이 바람직합니다. 대기업의 테이블들은 수시로 칼럼이 추가되거나 변경되는데, 프로그램 소스 내에*로 고정해 둘 경우 예기치 못한 에러를 유발할 수 있습니다. 또한 사용하지 않는 대용량 텍스트 칼럼까지 전부 네트워크로 전송하므로 부하를 가중시킵니다. 귀찮더라도 필요한 칼럼명을 명확히 기술하는 습관이 장기적인 SQL 성능 최적화와 유지보수성 향상에 도움이 됩니다.
- 팩트 체크: 테이블의 모든 칼럼을 한 번에 불러오는
5. 결론 및 다음 화 예고
이번 2화에서는 테라데이터 SQL 조회의 가장 기본 골격인 SELECT, FROM, WHERE 문법의 유기적인 연동 구조를 살펴보고, 대용량 원천 데이터 조회 시 시스템 스풀(Spool) 부족이나 병목을 방지하기 위한 안전장치인 SAMPLE 구문의 실무 활용법을 알아보았습니다. 데이터를 추출하는 행위는 단순히 결과를 얻는 것을 넘어, 서버의 제한된 자원을 효율적으로 나누어 쓴다는 관점에서 접근할 때 진정한 현업 분석가로 인정받을 수 있습니다.
이어지는 3화에서는 하나의 조건이 아닌 다양한 비즈니스 요구사항을 복합적으로 필터링하기 위해 필수적인 비교 연산자 및 논리 연산자(AND, OR, NOT)의 세계를 다룹니다. 특히 실무에서 AND와 OR 조건을 혼합하여 사용할 때 괄호(())의 배치 실수로 인해 엉뚱한 타겟 데이터가 추출되는 사례와 예방법을 데이터 논리 구조와 함께 낱낱이 파헤쳐 보겠습니다.