UnisquadsU
로그인
홈
이용약관·개인정보처리방침·콘텐츠정책·© 2026 Unisquads
이용약관·개인정보처리방침·콘텐츠정책
© 2026 Unisquads. All rights reserved.

Raw SQL (r1)

이 문서의 과거 버전 (r1)을 보고 있습니다. 수정일: 2026.02.24 08:42

Raw SQL

정의

데이터베이스에 직접 SQL 쿼리 문자열을 작성하여 실행하는 방식

유형

데이터베이스 접근 방식

주요 용도

복잡한 쿼리 실행

ORM(Object-Relational Mapping)의 한계를 극복한 데이터 조작

데이터베이스 특정 기능 활용

관련 분야

데이터베이스 프로그래밍

웹 백엔드 개발

장점

복잡한 쿼리와 데이터베이스 고유 기능 활용 가능

ORM보다 성능 최적화가 용이한 경우가 있음

상세 정보

단점

SQL 인젝션 공격에 취약할 수 있음

데이터베이스 종속성이 발생할 수 있음

코드 유지보수가 어려울 수 있음

보안 주의사항

사용자 입력값을 쿼리에 직접 삽입하지 않아야 함

파라미터화된 쿼리(Prepared Statement) 사용 권장

대안/관련 기술

ORM(Object-Relational Mapping)

쿼리 빌더(Query Builder)

1. 개요

Raw SQL은 데이터베이스에 직접 SQL 쿼리 문자열을 작성하여 실행하는 데이터베이스 접근 방식이다. 이 방식은 ORM을 통한 추상화된 접근과는 달리, 개발자가 데이터베이스에 전송할 명령을 완전히 제어할 수 있다. 주로 복잡한 쿼리 실행이나 ORM의 한계를 극복한 데이터 조작, 그리고 특정 데이터베이스의 고유 기능을 활용해야 할 때 사용된다.

이 방식은 데이터베이스 프로그래밍과 웹 백엔드 개발 분야에서 중요한 기술로 자리 잡고 있다. ORM이 제공하는 편리함과 생산성에도 불구하고, 복잡한 조인이나 집계 함수, 저장 프로시저 호출 등에서는 Raw SQL이 더 직관적이고 효율적인 해결책이 될 수 있다. 또한 데이터베이스 벤더별 최적화된 구문을 그대로 사용할 수 있어 성능 최적화에 유리한 경우가 많다.

2. 정의와 특징

2.1. 개념

Raw SQL은 ORM과 같은 추상화 도구를 거치지 않고, 개발자가 직접 SQL 쿼리 문자열을 작성하여 데이터베이스에 전송하고 실행하는 데이터 접근 방식을 의미한다. 이는 애플리케이션 코드 내에 문자열 형태로 SQL 문을 하드코딩하거나, 동적으로 문자열을 조합하여 데이터베이스와 소통하는 방식이다.

이 접근 방식은 ORM이 제공하는 편리한 객체 지향 인터페이스의 제약을 받지 않는다. 따라서 매우 복잡한 조인, 서브쿼리, 윈도우 함수, 데이터베이스 벤더별 고유 기능 등을 자유롭게 활용할 수 있다. 특히 보고서 생성이나 대규모 데이터 분석과 같이 복잡한 비즈니스 로직을 처리해야 할 때 Raw SQL의 유연성이 빛을 발한다.

또한, Raw SQL은 때때로 ORM을 통한 쿼리보다 더 직접적이고 효율적인 성능을 낼 수 있다. ORM이 생성하는 쿼리가 비효율적이거나 불필요한 추가 작업을 수행할 때, 개발자가 직접 최적화된 쿼리를 작성함으로써 성능을 극대화할 수 있다. 이는 대용량 데이터를 처리하거나 응답 시간이 중요한 상황에서 중요한 장점이 된다.

그러나 Raw SQL 사용은 SQL 인젝션과 같은 보안 취약점에 노출될 위험이 크며, 쿼리 문자열 관리와 유지보수가 어려워질 수 있다. 데이터베이스 스키마가 변경되면 관련된 모든 Raw SQL 쿼리를 수동으로 찾아 수정해야 하는 부담도 따른다.

2.2. 장점

Raw SQL을 사용하는 주요 장점은 복잡한 쿼리를 직접 제어할 수 있고, 데이터베이스 고유의 기능을 최대한 활용할 수 있다는 점이다. ORM은 일반적인 CRUD 작업을 단순화하지만, 다중 테이블 조인이나 복잡한 집계 함수, 윈도우 함수를 포함하는 고급 쿼리를 작성할 때는 제약이 따른다. Raw SQL은 이러한 복잡한 논리를 SQL 문법으로 직접 표현할 수 있어 개발자가 원하는 정확한 데이터를 유연하게 추출할 수 있다.

또한, 특정 데이터베이스 관리 시스템이 제공하는 비표준 기능이나 최적화 힌트를 활용할 수 있다. 각 DBMS는 성능 향상을 위한 독자적인 확장 기능을 가지고 있는데, Raw SQL을 사용하면 이러한 데이터베이스 특정 구문을 그대로 사용할 수 있다. 이는 쿼리 최적화 측면에서 유리하며, ORM의 추상화 계층을 거치지 않아 발생할 수 있는 오버헤드를 줄일 수 있다.

마지막으로, 잘 작성된 Raw SQL은 종종 ORM을 통한 생성 쿼리보다 더 높은 성능을 발휘하는 경우가 있다. ORM이 생성하는 쿼리는 때로 비효율적이거나 불필요한 조인을 포함할 수 있다. 개발자가 직접 쿼리를 최적화하면 불필요한 데이터 접근을 줄이고, 인덱스를 효과적으로 활용하는 등 데이터베이스 성능을 극대화할 수 있다. 이는 대용량 데이터를 처리하거나 응답 시간이 중요한 시스템에서 결정적인 장점이 된다.

2.3. 단점

Raw SQL 사용의 가장 큰 단점은 SQL 인젝션 공격에 취약할 수 있다는 점이다. 쿼리 문자열을 직접 조합하는 과정에서 사용자 입력값을 적절히 처리하지 않으면 악의적인 SQL 코드가 삽입될 수 있다. 이는 데이터 유출, 변조, 삭제와 같은 심각한 보안 문제로 이어질 수 있다.

두 번째 단점은 데이터베이스 벤더에 종속될 가능성이 높다는 것이다. MySQL, PostgreSQL, 오라클 데이터베이스 등 각 데이터베이스 관리 시스템은 고유의 SQL 방언이나 확장 기능을 가지고 있다. Raw SQL로 이러한 기능을 사용하면 애플리케이션의 이식성이 떨어져 다른 데이터베이스로의 전환이 어려워진다.

또한, Raw SQL은 객체 관계 매핑에 비해 생산성이 낮을 수 있다. 반복적인 CRUD 작업에 대해 매번 쿼리 문자열을 작성하고, 실행 결과를 자바, 파이썬 등의 애플리케이션 객체로 변환하는 수고가 필요하다. 이는 코드의 양을 증가시키고 유지보수를 어렵게 만드는 요인이 된다.

마지막으로, 컴파일 타임에 쿼리 문법 오류를 검증하기 어렵다는 문제도 있다. ORM은 메서드 호출을 통해 쿼리를 구성하므로 일부 오류를 사전에 발견할 수 있지만, Raw SQL은 문자열 형태이기 때문에 대부분의 오류는 런타임에 실행을 시도해야만 확인된다.

3. 사용 방법

3.1. 기본 쿼리 작성

Raw SQL을 사용한 기본 쿼리 작성은 데이터베이스에 직접 SQL 문장을 문자열 형태로 구성하여 실행하는 과정이다. 이 방식은 ORM이 자동 생성하는 쿼리 대신, 개발자가 필요한 정확한 로직을 직접 제어할 수 있게 한다. 가장 기본적인 작업은 SELECT, INSERT, UPDATE, DELETE와 같은 데이터 조작 언어 문장을 작성하는 것이다. 예를 들어, 사용자 테이블에서 특정 조건을 만족하는 모든 레코드를 조회하려면 SELECT * FROM users WHERE status = 'active';와 같은 쿼리 문자열을 애플리케이션 코드 내에 작성한다.

쿼리를 작성할 때는 대상 데이터베이스 관리 시스템의 SQL 방언을 고려해야 한다. MySQL, PostgreSQL, SQLite, Oracle Database 등 각 시스템은 표준 SQL 외에 고유한 함수나 문법을 제공하는 경우가 많다. Raw SQL을 사용하면 이러한 데이터베이스별 확장 기능을 직접 활용할 수 있다. 또한, 조인, 서브쿼리, 공통 테이블 표현식, 윈도우 함수 등 복잡한 데이터 관계와 분석을 처리하는 고급 쿼리를 자유롭게 구성할 수 있다.

애플리케이션 코드에서 Raw SQL 쿼리를 실행하는 방법은 사용하는 프로그래밍 언어와 데이터베이스 드라이버에 따라 다르다. 일반적으로 데이터베이스 연결 객체를 통해 쿼리 문자열을 전달하고 실행 명령을 호출한다. 실행 후에는 결과 집합을 반복 처리하거나 특정 변수에 매핑하여 애플리케이션에서 활용한다. 이 과정에서 쿼리 문자열 내에 사용자 입력 값을 직접 연결하지 않고, 매개변수 바인딩을 사용하여 SQL 인젝션 공격을 방지하는 것이 보안상 매우 중요하다.

3.2. 매개변수 바인딩

매개변수 바인딩은 Raw SQL을 사용할 때 SQL 인젝션 공격을 방지하고 쿼리 성능을 최적화하기 위한 핵심 기법이다. 이는 사용자 입력값이나 외부 데이터를 쿿리 문자열에 직접 연결(문자열 결합)하지 않고, 별도의 매개변수로 전달하여 데이터베이스 엔진이 쿼리 구조와 데이터를 명확히 구분하도록 하는 방법이다.

주요 방식으로는 위치 기반 바인딩과 이름 기반 바인딩이 있다. 위치 기반 바인딩은 ?나 $1, $2와 같은 플레이스홀더를 사용하며, 파이썬의 sqlite3 모듈이나 자바의 JDBC에서 흔히 볼 수 있다. 이름 기반 바인딩은 :name이나 @name과 같이 명시적인 이름을 사용하는 방식으로, PHP의 PDO 확장이나 파이썬의 SQLAlchemy 같은 라이브러리에서 지원한다. 이러한 바인딩을 사용하면 데이터베이스는 쿼리 실행 계획을 재사용(쿼리 플랜 캐싱)할 수 있어 성능이 향상된다.

매개변수 바인딩을 적용할 때는 데이터 유형을 정확히 지정하는 것이 중요하다. 예를 들어, 문자열, 정수, 날짜 등 데이터 유형에 맞는 바인딩 방식을 사용해야 하며, 일부 ORM 라이브러리나 데이터베이스 드라이버는 이를 자동으로 처리하기도 한다. 이를 통해 애플리케이션의 보안을 강화하면서도 데이터베이스의 고유 기능을 활용한 효율적인 Raw SQL 작성이 가능해진다.

3.3. 결과 처리

Raw SQL 쿼리를 실행한 후, 반환된 결과를 애플리케이션에서 사용 가능한 형태로 변환하고 처리하는 과정이 필요하다. 데이터베이스 드라이버나 라이브러리는 쿼리 결과를 일반적으로 튜플의 리스트나 사전 형태로 반환한다. 예를 들어, Python의 sqlite3 모듈은 커서 객체를 통해 결과 행을 튜플로 가져오며, psycopg2는 PostgreSQL 결과를 비슷한 방식으로 처리한다. 개발자는 이 원시 데이터를 순회하며 필요한 비즈니스 로직을 적용하거나, 객체로 변환하여 사용한다.

결과 처리 시 고려해야 할 주요 사항은 데이터 타입 변환, NULL 값 처리, 그리고 대량 데이터의 효율적 핸들링이다. 데이터베이스에서 반환된 정수, 문자열, 날짜 등의 타입은 프로그래밍 언어의 네이티브 타입으로 매핑되어야 한다. 또한, 쿼리가 아무 행도 반환하지 않을 경우에 대한 예외 처리가 중요하며, 페이징이나 청크 단위로 데이터를 나누어 처리하는 것은 메모리 관리와 성능에 필수적이다.

많은 웹 프레임워크와 라이브러리는 Raw SQL 실행 결과를 보다 편리하게 처리할 수 있는 도구를 제공한다. Django는 connection.cursor()를 사용한 후 dictfetchall() 같은 헬퍼 함수로 결과를 사전 리스트로 변환할 수 있다. SQLAlchemy의 Core 레이어는 text() 구문과 함께 사용하여 결과를 ResultProxy 객체로 받아, 각 행을 사전처럼 접근할 수 있게 한다. 이러한 처리 방식을 통해 개발자는 ORM이 제공하는 추상화 없이도 데이터베이스 결과를 유연하게 활용할 수 있다.

4. ORM과의 비교

ORM은 객체 지향 프로그래밍 언어와 관계형 데이터베이스 사이의 불일치를 해결하기 위한 도구이다. 애플리케이션 코드에서 객체를 다루듯이 데이터를 조작할 수 있게 하여, 개발자가 직접 SQL 문을 작성하는 부담을 줄이고 생산성을 높이는 데 중점을 둔다. 반면, Raw SQL은 데이터베이스에 직접 SQL 쿼리 문자열을 작성하여 실행하는 방식으로, ORM이 제공하는 추상화 계층을 거치지 않는다.

두 방식의 가장 큰 차이는 제어력과 편의성 사이의 트레이드오프에 있다. Raw SQL은 복잡한 조인, 서브쿼리, 윈도우 함수, 데이터베이스 특정 기능(예: PostgreSQL의 JSON 함수, MySQL의 공간 데이터 함수)을 완벽히 활용할 수 있어 세밀한 제어와 최고의 성능을 추구할 때 유리하다. 특히 ORM의 한계를 극복한 데이터 조작이 필요하거나, 대량 데이터 처리 시 성능 최적화가 중요한 경우 Raw SQL이 필수적이다.

반면, ORM은 CRUD 작업을 단순화하고, 데이터베이스 벤더에 독립적인 코드 작성, 객체 간 관계 관리, 마이그레이션 도구 제공 등 개발 편의성을 크게 향상시킨다. 그러나 복잡한 쿼리를 생성할 때는 비효율적인 SQL을 생성하거나, 특정 데이터베이스의 고급 기능을 사용하기 어려운 한계가 있을 수 있다. 따라서 현대의 웹 백엔드 개발에서는 두 방식을 상황에 따라 혼용하는 것이 일반적이다. 간단한 데이터 접근에는 ORM을 사용하고, 성능이 중요한 복잡한 애널리틱스 쿼리나 리포팅에는 Raw SQL을 사용하는 접근 방식이 효율적이다.

5. 보안 고려사항

5.1. SQL 인젝션

Raw SQL을 사용할 때 가장 중요한 보안 고려사항은 SQL 인젝션 공격에 노출될 수 있다는 점이다. SQL 인젝션은 악의적인 사용자가 애플리케이션의 입력 필드나 매개변수에 SQL 코드 조각을 삽입하여, 의도하지 않은 데이터베이스 명령을 실행하게 만드는 공격 기법이다. 이는 데이터 유출, 데이터 변조, 심지어 전체 데이터베이스 파괴로 이어질 수 있는 심각한 취약점이다.

Raw SQL 쿼리를 문자열 결합 방식으로 작성할 때, 사용자 입력값을 그대로 쿼리에 포함시키면 SQL 인젝션 위험이 크게 증가한다. 예를 들어, 사용자 아이디를 입력받아 "SELECT * FROM users WHERE id = '" + userInput + "'"와 같은 쿼리를 생성한다면, 공격자가 userInput에 ' OR '1'='1과 같은 값을 입력하면 전체 사용자 정보가 유출될 수 있다. 이는 쿼리의 논리 구조를 변경하여 항상 참이 되는 조건을 만들어내기 때문이다.

SQL 인젝션을 방어하기 위한 가장 효과적인 기법은 매개변수 바인딩 또는 준비된 문장(Prepared Statement)을 사용하는 것이다. 이 방법은 사용자 입력을 쿼리 문자열과 분리하여, 데이터베이스가 입력값을 단순한 데이터로만 해석하도록 한다. 따라서 입력값 내에 포함된 SQL 명령어가 실행되지 않는다. 대부분의 현대 데이터베이스 드라이버와 프레임워크는 이 기능을 지원한다.

또 다른 방어 기법으로는 입력값의 화이트리스트 검증, 최소 권한 계정으로 데이터베이스에 접속, 오류 메시지로부터 시스템 정보가 노출되지 않도록 처리하는 것이 있다. 그러나 이러한 방법들은 매개변수 바인딩을 대체할 수 없으며, 보안을 다층적으로 강화하기 위한 보조 수단으로 활용되어야 한다. 결국 Raw SQL을 안전하게 사용하려면 개발자가 보안 원칙을 충분히 이해하고, 외부 입력을 절대 신뢰하지 않으며, 항상 매개변수화된 쿼리를 사용하는 습관이 필수적이다.

5.2. 방어 기법

Raw SQL 사용 시 가장 중요한 보안 고려사항은 SQL 인젝션 공격을 방어하는 것이다. 이를 위한 가장 효과적인 방어 기법은 매개변수 바인딩 또는 준비된 문장(Prepared Statement)을 사용하는 것이다. 이 방법은 사용자 입력을 쿼리 문자열과 분리하여, 입력 데이터가 SQL 명령어로 해석되는 것을 근본적으로 차단한다. 대부분의 현대 데이터베이스 드라이버와 ORM 라이브러리는 이 기능을 지원한다.

입력값을 직접 문자열 연결로 쿼리에 삽입하는 방식은 절대 피해야 한다. 또한, 사용자 입력에 대한 엄격한 입력 검증과 화이트리스트 기반 필터링을 적용하는 것이 보조적인 방어 수단이 될 수 있다. 예를 들어, 숫자만 입력되어야 하는 필드에 문자열이 들어오지 않도록 검사하거나, 허용된 문자 집합만을 통과시키는 방법이다.

데이터베이스 사용자 권한을 최소한으로 제한하는 것도 중요한 방어 전략이다. 애플리케이션이 사용하는 데이터베이스 계정이 최소한의 필요한 작업(예: 특정 테이블의 SELECT, INSERT만)만 수행할 수 있도록 권한을 설정하면, 공격이 성공하더라도 피해 범위를 제한할 수 있다. 정기적인 코드 감사와 보안 테스트를 통해 Raw SQL 쿼리가 포함된 코드를 점검하는 것도 필수적이다.

6. 사용 사례

6.1. 복잡한 쿼리

Raw SQL은 ORM이 제공하는 추상화 계층을 벗어나 복잡한 데이터 조작을 직접 구현할 수 있는 강력한 수단이다. 특히 다수의 테이블을 조인하거나, 윈도우 함수, 공통 테이블 표현식(CTE), 재귀 쿼리 등 고급 SQL 기능을 필요로 하는 경우에 빛을 발한다. ORM은 기본적인 CRUD 작업에는 효율적이지만, 복잡한 비즈니스 로직을 담은 리포트 생성이나 계층적 데이터 탐색 같은 작업을 표현하기에는 제한적일 수 있다.

예를 들어, 여러 데이터베이스 간에 분산된 데이터를 통합하거나, 특정 데이터베이스 관리 시스템(DBMS)만이 제공하는 최적화 힌트를 사용해야 할 때 Raw SQL은 불가피한 선택이 된다. 데이터 웨어하우스에서의 복잡한 집계 쿼리나, 지리 공간 데이터를 처리하는 전문 함수를 활용하는 경우도 마찬가지이다. 이는 개발자가 데이터베이스의 모든 능력을 최대한 끌어낼 수 있게 해준다.

따라서 Raw SQL의 사용은 ORM의 편리함과 데이터베이스의 완전한 제어 사이에서의 전략적 선택이다. 프로젝트에서 성능이 결정적이거나, ORM의 쿼리 생성기로는 도달할 수 없는 복잡성이 요구될 때 적극적으로 고려된다.

6.2. 성능 최적화

Raw SQL을 사용한 성능 최적화는 ORM이 생성하는 일반화된 쿼리보다 데이터베이스의 특정 기능과 구조에 최적화된 쿼리를 직접 설계할 수 있다는 점에서 강점을 가진다. 개발자는 인덱스 사용을 명시적으로 제어하거나, 조인의 순서와 방식을 세밀하게 조정하며, 불필요한 컬럼 선택을 피하는 등 데이터베이스의 실행 계획에 직접 영향을 줄 수 있다. 특히 대량의 데이터를 처리하거나 복잡한 집계 함수를 사용해야 하는 데이터 웨어하우스 환경에서 이러한 최적화는 처리 속도와 자원 효율성에서 큰 차이를 만들어낸다.

성능 최적화를 위한 주요 접근법은 다음과 같다. 첫째, 쿼리 최적화를 위해 EXPLAIN 명령어를 사용하여 데이터베이스가 쿼리를 실행하는 계획을 분석하고 병목 현상을 찾아낸다. 둘째, N+1 쿼리 문제를 해결하기 위해 적절한 조인을 사용하여 여러 번의 데이터베이스 호출을 단일 쿼리로 통합한다. 셋째, 데이터베이스 고유의 기능, 예를 들어 윈도우 함수나 Common Table Expressions(CTE)를 활용하여 애플리케이션 레벨에서 처리하던 로직을 데이터베이스 내부로 옮겨 네트워크 비용과 메모리 사용량을 줄인다.

최적화 기법

설명

기대 효과

인덱스 힌트 사용

데이터베이스가 특정 인덱스를 사용하도록 쿼리에 지시

검색 및 조인 속도 향상

페이지네이션 최적화

OFFSET 대신 WHERE 절과 인덱스를 이용한 키셋 페이지네이션 구현

대량 데이터 조회 시 성능 저하 방지

배치 처리

여러 개의 INSERT나 UPDATE 문을 하나의 배치 쿼리로 처리

데이터베이스 라운드트립 횟수 감소

그러나 Raw SQL을 통한 성능 최적화는 데이터베이스 종속성을 높이고 쿼리 유지보수성을 낮출 수 있다는 점을 고려해야 한다. 따라서 최적화는 실제 성능 프로파일링을 통해 확인된 문제점에 대해서만 적용하며, ORM의 지연 로딩이나 즉시 로딩 전략을 먼저 조정하는 것도 좋은 대안이 될 수 있다. 궁극적으로는 애플리케이션 성능 관리(APM) 도구를 활용해 시스템 전반의 병목 지점을 파악한 후, 데이터베이스 접근 방식의 최적화가 가장 효과적인 부분에 Raw SQL을 선택적으로 도입하는 것이 바람직하다.

7. 관련 문서

  • 위키백과 - SQL

  • MDN Web Docs - SQL

  • Oracle - SQL 소개

  • Microsoft Learn - Transact-SQL 참조

  • W3Schools - SQL 튜토리얼

  • SQLite - SQL 이해하기

  • PostgreSQL - SQL 명령어

  • MySQL - SQL 문법

  • 국립중앙도서관 - 데이터베이스 질의어 SQL 기초

  • 한국데이터베이스진흥원 - SQL 표준

리비전 정보

버전r1
수정일2026.02.24 08:42
편집자unisquads
편집 요약AI 자동 생성