2025-08-28 00:09
-
쿼리는 방대한 데이터베이스에서 원하는 정보만 정확히 꺼내기 위해 만들어진 ‘질의문’입니다.
-
가장 대표적인 SQL 쿼리는 SELECT, FROM, WHERE 등의 정해진 문법 구조를 통해 작동합니다.
-
잘 만들어진 쿼리는 시스템 성능을 좌우하며, 내부 실행 계획과 인덱스를 이해하는 것이 최적화의 핵심입니다.
개발자 필수 스킬 쿼리 완벽 가이드 탄생부터 최적화까지
우리가 매일 사용하는 거의 모든 서비스는 보이지 않는 거대한 데이터 창고, 즉 데이터베이스(Database) 위에서 동작합니다. 페이스북에 글을 쓰거나, 온라인 쇼핑몰에서 상품을 검색하거나, 은행 앱에서 거래 내역을 확인할 때마다 우리는 데이터베이스와 상호작용합니다. 이때, 이 거대한 창고에서 내가 원하는 물건(데이터)만 콕 집어 꺼내오도록 요청하는 특별한 명령어가 필요한데, 이것이 바로 **쿼리(Query)**입니다.
쿼리는 단순히 데이터를 가져오는 것을 넘어, 데이터를 다루는 기술의 핵심이자 모든 개발자가 반드시 마스터해야 할 기본기입니다. 이 핸드북에서는 쿼리가 왜 만들어졌는지부터 시작하여 그 구조와 사용법, 그리고 더 나아가 시스템의 성능을 좌우하는 최적화 비법까지, 쿼리의 모든 것을 알기 쉽게 파헤쳐 보겠습니다.
1. 쿼리의 탄생 배경: 왜 우리는 쿼리를 사용해야만 했을까?
컴퓨터가 발명되고 기업들이 데이터를 전산화하기 시작한 초기 시절을 상상해 봅시다. 데이터는 파일 시스템에 텍스트 파일이나 특정 형식의 파일로 저장되었습니다. 만약 여기서 “서울에 사는 30대 고객 명단”을 뽑아내려면 어떻게 해야 했을까요?
아마도 프로그래머는 다음과 같은 고된 작업을 반복해야 했을 겁니다.
-
고객 데이터가 담긴 파일을 처음부터 끝까지 읽어 들인다.
-
한 줄씩 읽으면서 각 고객의 주소와 나이 정보를 파싱(parsing)한다.
-
주소가 ‘서울’로 시작하고, 나이가 ‘30대’에 해당하는지 조건문을 통해 확인한다.
-
조건에 맞는 고객만 새로운 파일이나 메모리에 저장한다.
이 방식은 몇 가지 치명적인 문제를 안고 있었습니다.
-
비효율성: 매번 전체 데이터를 읽어야 하므로 데이터 양이 많아질수록 속도가 기하급수적으로 느려집니다.
-
복잡성: “최근 3개월간 구매액이 100만 원 이상인 서울 거주 30대 고객”처럼 조건이 복잡해지면 코드는 상상 이상으로 길고 어려워집니다.
-
종속성: 데이터가 저장된 물리적 구조(파일 형식, 폴더 위치 등)가 바뀌면 데이터를 읽는 프로그램 코드 전체를 수정해야 했습니다.
이러한 문제를 해결하기 위해 “데이터를 어떻게 저장할지는 데이터베이스 관리 시스템(DBMS)에 맡기고, 사용자는 그저 ‘무엇을 원하는지’ 선언만 하자!” 라는 혁신적인 아이디어가 등장합니다. 이것이 바로 **선언형 언어(Declarative Language)**의 개념이며, 이 아이디어를 구체화한 것이 바로 쿼리 언어(Query Language), 그리고 그 대표주자가 SQL(Structured Query Language) 입니다.
쿼리 언어 덕분에 개발자는 데이터가 디스크의 어느 위치에 어떻게 저장되어 있는지 신경 쓸 필요 없이, 그저 정해진 문법에 맞춰 “내가 원하는 데이터는 이것이다”라고 선언하기만 하면 되었습니다. 그러면 똑똑한 DBMS가 그 요청을 해석해서 가장 효율적인 방법으로 데이터를 찾아다 주는 시대가 열린 것입니다. 이는 개발 생산성을 폭발적으로 증가시킨 혁신적인 사건이었습니다.
2. 쿼리의 구조 해부: 어떻게 원하는 것을 정확히 표현할까?
가장 널리 사용되는 SQL을 기준으로 쿼리의 기본 구조를 살펴보겠습니다. 쿼리는 마치 영어 문장처럼 정해진 순서와 문법을 따릅니다. 우리가 카페에 가서 “아이스 아메리카노, 큰 사이즈로, 시럽 빼고 주세요”라고 주문하는 것과 비슷합니다.
SQL의 기본 SELECT 쿼리는 주로 다음과 같은 절(Clause)로 구성됩니다.
절 (Clause) | 역할 | 카페 주문 비유 |
---|---|---|
SELECT | 어떤 데이터(컬럼)를 가져올 것인가? | ”아이스 아메리카노를 주세요” (메뉴 선택) |
FROM | 어떤 테이블에서 가져올 것인가? | (카페 메뉴판에서) |
WHERE | 어떤 조건에 맞는 데이터를 가져올 것인가? | ”시럽은 빼고 주세요” (옵션 조건) |
GROUP BY | 특정 컬럼을 기준으로 데이터를 그룹화한다. | ”메뉴별로 몇 잔씩 팔렸는지 알려주세요” |
HAVING | 그룹화된 결과에 대한 조건을 지정한다. | ”그중에서 10잔 이상 팔린 메뉴만 보여주세요” |
ORDER BY | 결과를 특정 순서로 정렬한다. | ”가격이 저렴한 순서대로 보여주세요” (정렬) |
이 절들을 조합하여 하나의 완전한 요청문을 만듭니다. 예를 들어 employees
라는 직원 테이블이 있다고 가정해 봅시다.
요청: “인사팀(HR)에 소속된 직원들의 이름과 연봉을, 연봉이 높은 순서대로 보여주세요.”
이 요청은 다음과 같은 SQL 쿼리로 변환될 수 있습니다.
SELECT
name, salary -- 이름(name)과 연봉(salary)을
FROM
employees -- 직원(employees) 테이블에서
WHERE
department = 'HR' -- 소속 부서(department)가 'HR'인 조건으로
ORDER BY
salary DESC; -- 연봉(salary)을 기준으로 내림차순(DESC) 정렬해서
이처럼 쿼리는 사람이 생각하는 논리적 순서(FROM → WHERE → SELECT → ORDER BY)와 실제 작성 순서가 조금 다르지만, 각 절이 명확한 역할을 수행하며 원하는 데이터를 정확하게 명시할 수 있도록 설계되었습니다.
3. 쿼리 사용법: 실전 예제로 배우는 데이터 조작 기술
쿼리는 단순히 데이터를 조회(Read)하는 데 그치지 않고, 새로운 데이터를 생성(Create), 수정(Update), 삭제(Delete)하는 역할도 수행합니다. 이 네 가지를 합쳐 CRUD라고 부릅니다. 하지만 쿼리의 가장 핵심적이고 다채로운 활용은 역시 조회(Read)에 있습니다.
기본 조회 (SELECT)
앞서 본 예제처럼 가장 기본적인 데이터 조회 작업입니다. *
문자를 사용하면 모든 컬럼을 가져올 수 있습니다.
-- products 테이블의 모든 정보를 조회
SELECT * FROM products;
-- products 테이블에서 이름과 가격만 조회
SELECT name, price FROM products;
데이터 합치기 (JOIN)
쿼리의 진정한 힘은 여러 테이블에 흩어져 있는 데이터를 연결하여 의미 있는 정보를 만들어낼 때 발휘됩니다. 예를 들어, orders
테이블에는 주문 정보가 있고 users
테이블에는 사용자 정보가 있을 때, 특정 주문을 한 사용자의 이름을 알려면 두 테이블을 연결해야 합니다. 이때 사용하는 것이 JOIN입니다.
users
테이블
user_id | name |
---|---|
1 | 김철수 |
2 | 이영희 |
orders
테이블
order_id | user_id | item |
---|---|---|
101 | 2 | 노트북 |
102 | 1 | 키보드 |
SELECT
u.name, o.item -- 사용자의 이름(name)과 주문 상품(item)을
FROM
orders AS o -- orders 테이블을 o라고 부르고
INNER JOIN
users AS u ON o.user_id = u.user_id; -- users 테이블을 u라고 부르며, 두 테이블의 user_id가 같은 것을 기준으로 합친다.
실행 결과
name | item |
---|---|
이영희 | 노트북 |
김철수 | 키보드 |
JOIN에는 여러 종류가 있습니다.
-
INNER JOIN: 두 테이블에 공통적으로 존재하는 데이터만 합칩니다. (가장 많이 사용)
-
LEFT JOIN (LEFT OUTER JOIN): 왼쪽 테이블의 데이터는 모두 포함하고, 오른쪽 테이블은 공통된 것만 합칩니다. 공통된 것이 없으면
NULL
로 표시됩니다. -
RIGHT JOIN (RIGHT OUTER JOIN): 오른쪽 테이블 기준. LEFT JOIN과 반대입니다.
-
FULL OUTER JOIN: 양쪽 테이블의 모든 데이터를 포함하여 합칩니다.
4. 심화 내용: 쿼리는 어떻게 번개처럼 빠르게 동작할까?
우리가 던진 간단한 쿼리 한 줄 뒤에서, 데이터베이스는 최적의 성능을 내기 위해 매우 복잡하고 지능적인 작업을 수행합니다. 이 내부 동작 원리를 이해하는 것이 초급과 중급 개발자를 가르는 중요한 기준이 됩니다.
쿼리 실행 계획 (Query Execution Plan)
DBMS는 우리가 작성한 쿼리를 그대로 실행하지 않습니다. 먼저 쿼리를 분석하여 **가장 효율적으로 데이터를 찾을 수 있는 방법(실행 계획)**을 수립합니다. 마치 내비게이션이 목적지까지 가는 여러 경로(경로 1, 경로 2, 고속도로 우선 등)를 탐색한 뒤 최적의 경로를 추천해 주는 것과 같습니다.
-
파싱 (Parsing): 쿼리 문법이 올바른지, 오타는 없는지 확인합니다.
-
최적화 (Optimization): 어떻게 데이터를 가져오는 것이 가장 빠를지 결정합니다. 예를 들어, JOIN을 할 때 어떤 테이블을 먼저 읽을지, 인덱스(Index)를 사용할지 등을 결정합니다. 이 단계가 DBMS의 ‘뇌’에 해당하며 성능에 가장 큰 영향을 미칩니다.
-
실행 (Execution): 최적화 프로그램이 세운 계획에 따라 실제 데이터에 접근하여 결과를 가져옵니다.
개발자는 EXPLAIN
같은 명령어를 통해 DBMS가 세운 실행 계획을 직접 눈으로 확인할 수 있습니다. 만약 쿼리가 비정상적으로 느리다면, 실행 계획을 분석하여 어느 부분에서 병목이 발생하는지 찾아내고 쿼리를 수정하거나 인덱스를 추가하는 등의 방법으로 최적화할 수 있습니다.
인덱스 (Index): 데이터베이스의 색인
인덱스는 쿼리 성능을 극적으로 향상시키는 가장 중요한 기술입니다. 책 맨 뒤에 있는 ‘찾아보기’ 페이지를 생각하면 쉽습니다. 만약 책에서 ‘쿼리’라는 단어가 나오는 모든 페이지를 찾고 싶을 때, 책 전체를 한 장씩 넘겨보는 것보다 찾아보기 페이지에서 ‘쿼리’ 항목을 찾아 해당 페이지 번호로 바로 이동하는 것이 훨씬 빠릅니다.
데이터베이스의 인덱스도 이와 똑같은 원리로 작동합니다. 특정 컬럼(예: user_id
, name
)에 인덱스를 생성해두면, WHERE
절에서 해당 컬럼을 조건으로 데이터를 찾을 때 테이블 전체를 훑는 대신(Full Table Scan), 인덱스를 통해 데이터의 물리적 위치를 빠르게 찾아냅니다.
-- email 컬럼에 인덱스가 없다면, users 테이블 전체를 뒤져서 해당 이메일을 찾는다.
-- 하지만 인덱스가 있다면, B-Tree 같은 효율적인 자료구조로 된 인덱스에서 바로 찾아낸다.
SELECT * FROM users WHERE email = 'test@example.com';
하지만 인덱스는 만능이 아닙니다. 데이터를 추가(INSERT), 수정(UPDATE), 삭제(DELETE)할 때마다 인덱스도 함께 업데이트되어야 하므로 오히려 성능 저하를 유발할 수 있습니다. 따라서 조회(SELECT)가 자주 일어나는 컬럼, 그리고 WHERE 절의 조건으로 자주 사용되는 컬럼에만 선택적으로 생성하는 전략이 중요합니다.
SQL을 넘어서: NoSQL과 GraphQL
전통적인 관계형 데이터베이스(RDBMS)와 SQL이 여전히 데이터 세계의 표준이지만, 빅데이터와 비정형 데이터 시대가 도래하면서 새로운 형태의 쿼리 방식도 등장했습니다.
-
NoSQL 쿼리: MongoDB 같은 문서(Document) 데이터베이스에서는 JSON과 유사한 형태로 데이터를 조회합니다.
db.users.find({ "age": { "$gt": 30 } })
와 같은 형식으로 사용되며, 유연하고 확장성이 뛰어난 것이 장점입니다. -
GraphQL: 페이스북이 개발한 API를 위한 쿼리 언어입니다. 서버에 필요한 데이터의 구조를 클라이언트가 직접 쿼리로 요청하는 방식입니다. REST API가 정해진 데이터 덩어리만 제공하는 것과 달리, GraphQL은 필요한 데이터만 정확하게 요청할 수 있어 네트워크 효율성이 높다는 장점이 있습니다.
결론: 쿼리는 살아있는 기술이다
지금까지 우리는 데이터를 다루는 가장 근본적인 기술인 쿼리에 대해 알아보았습니다. 쿼리는 단순히 데이터베이스에 질문을 던지는 명령어가 아니라, 개발자와 데이터베이스 사이의 가장 중요한 소통 방식입니다.
쿼리를 잘 작성하는 능력은 단순히 원하는 결과를 얻는 것을 넘어, 시스템 전체의 안정성과 성능을 책임지는 핵심 역량입니다. 데이터베이스가 어떤 실행 계획을 세우는지, 인덱스는 어떻게 동작하는지 그 내부 원리를 이해하려 노력할 때 비로소 진정한 데이터 전문가로 거듭날 수 있습니다. 세상이 데이터로 가득 찬 만큼, 데이터를 자유자재로 요리하는 기술인 쿼리의 중요성은 앞으로 더욱 커질 것입니다. 지금 바로 여러분의 데이터베이스에 멋진 질문을 던져보세요!