SQL을 사용할 때, 정확한 결과를 얻기만 하면 그걸로 끝인 줄 알았다. 어떤 쿼리는 길이가 길어져서 가독성이 좋지 않다고 느끼는 날도 있었고, 체감상 실행 속도가 느리다고 느꼈던 경우도 있었지만 원하는 결과를 추출하는 데 성공했다면 크게 신경쓰지 않고 넘어갔었던 것 같다. 물론 그냥 넘어가면서도 이렇게 해도 되는 건가? 라는 의문이 들면서 찝찝했었다. 그래서 일을 쉬고 있는 동안 성능 좋은 SQL 작성 방법에 대해 공부해보기로 했다.
1. 성능이 안좋은 SQL이 미치는 영향
원하는 결과 추출이라는 목적만 달성하면 되는 것 아닌가? 굳이 성능까지 고려해가면서 쿼리를 작성해야 하나? 라는 질문을 먼저 해보면서 시작해보자. 같은 결과를 만들더라도 SQL을 어떻게 작성하느냐에 따라 성능이 크게 달라질 수 있다. 작성한 SQL의 성능이 나쁘면 어떤 문제가 생길까?
성능이 나쁜 SQL은 결과는 똑같이 나와도,
시스템 리소스를 훨씬 더 많이 쓰고, 더 느리게 작동해서
전체 시스템에 부하를 주고, 서비스 품질을 떨어뜨릴 수 있다.
① 리소스 과소비 (근본 원인)
: 성능이 나쁜 SQL은 인덱스를 사용하지 못하거나, 불필요하게 많은 데이터를 처리해서 CPU, 메모리, 디스크 I/O를 지나치게 사용함
② 응답 속도 저하
: 리소스를 많이 쓰니까 쿼리 하나당 처리 시간이 길어지고, 사용자는 결과를 늦게 받음
③ 동시성 저하 (=락 증가)
: 쿼리가 오래 걸리면 락이 오래 유지되어, 다른 트랜잭션들이 기다리게 됨 (→ 동시 접속에 병목 발생)
④ 타임아웃 및 에러 발생
: 응답이 느려지면 일부 요청은 아예 시간 초과(timeout)로 실패하거나, 시스템이 에러를 냄
⑤ 전체 시스템 성능 저하
: 한 쿼리가 리소스를 독식하면 다른 쿼리도 느려지고, 결국 전체 시스템이 불안정해짐
⑥ 운영 비용 증가
: 성능 유지하려면 서버를 증설하거나, DB 튜닝 인력을 투입해야 함 → 비용 증가
데이터 검색 or 갱신 처리 => 결국 컴퓨터(정확히는 데이터베이스 서버)가 일을 하는 것. 그런데 SQL을 비효율적으로 작성하면,더 많은 시간과 컴퓨터 자원이 필요하게 되는 것. 극단적인 예시를 들면, 자료를 100건만 보면 되는데도 엑셀 10만 줄을 다 훑고 나서 결과를 보여주는 것과 비슷함.
즉, 성능을 고려하여 SQL을 작성한다는 것은
=> 결과만 맞으면 되는 게 아니라
=> 최대한 "1)적은 자원으로, 2)빠르게” 결과를 내는 것이다.
2. 실무에서 SQL 작성할 때, 특히 성능을 고려해야 하는 이유
성능이 좋지 않은 SQL은 위에서 알아본 내용과 같이 여러 부정적인 결과를 낳을 수 있기 때문에, 우리는 SQL을 작성할 때 성능을 고려해야한다. 특히 회사 실무에서 SQL 작성할 때, 효율성과 성능을 더욱 고려해야 하는 이유는 무엇일까? 두 가지가 있을 것 같다.
1️⃣ 데이터가 많은 경우
: 데이터가 많을 때, 성능 차이가 극심해지기 때문
적은 양의 데이터에서는 쿼리 성능 차이를 체감하기 어렵다. 하지만 데이터가 수백만, 수천만 건 이상으로 커지면 비효율적인 쿼리는 성능이 매우 떨어질 수 있다. 예를 들어, 불필요한 전체 스캔(Full Scan)이나 인덱스 무시 등은 쿼리 속도를 수십 배 늦출 수 있다고 한다. 결과적으로 분석 속도는 떨어지고, 반복적인 실험이나 대시보드 업데이트를 해야하는 경우 문제가 발생할 수 있다. 즉, 데이터가 많을수록 "잘 짜인 SQL"과 "대충 짠 SQL"의 차이가 매우 커진다. 이게 바로 실무에서 성능 고려가 필수인 이유인 것 같다.
▶ 데이터가 적을 경우
- 몇 백 건, 몇 천 건 정도라면 쿼리가 비효율적이어도 눈에 띄는 성능 차이가 거의 없음. 예를 들어 SELECT * 이든, 인덱스를 안 쓰든, 실행 속도는 여전히 0.1~0.2초 이내이기 때문에.
- 현재 이런 상황이고, 앞으로 데이터가 크게 늘어나지 않을 것이라면 크게 성능을 고려할 필요는 없을 것 같다. 기능적으로 구현만 되면 충분하지 않을까?
▶ 데이터가 많을 경우 (수백만 ~ 수억 건)
- 같은 결과를 얻는 쿼리라도 효율적으로 작성했느냐에 따라, 데이터가 많아질수록 실행 속도가 수 초에서 수 분까지 차이가 나며 실행 실패 가능성도 있음. (데이터가 적을 때는 별 차이가 없음)
- 인덱스를 사용하지 않거나, 필터 조건이 비효율적이면 디스크 풀스캔 발생 등 리소스 과다 사용.
2️⃣ 여러 사람이 동시에 사용하는 경우 (다중 사용자 환경)
: 여러 명이 동시에 DB를 사용할 때, 나의 쿼리가 다른 사람에게도 영향을 주기 때문
데이터베이스의 경우, 혼자만 사용하는 게 아니라 팀원들과 함께 쓰는 공용 자원이다. 무거운 쿼리를 하나 실행하면, CPU/메모리/디스크 등의 서버 자원을 과도하게 점유하게 되고, 다른 사람의 쿼리까지 느려지거나 대기 상태로 밀릴 수 있다. 특히 정기적으로 업데이트되어야 하는 리포트, 대시보드처럼 실시간 쿼리가 함께 돌아가는 환경에서는 전체 시스템에 피해를 줄 수 있다. 이처럼 여러 명이 같이 쓰는 환경에서는 "개인의 쿼리 성능"이 "공동 자원 운영"과 직결된다. 성능을 고려하는 건 나만을 위한 게 아니라 팀 전체를 위한 책임감이기도 하다. SQL 하나가 잘못 짜여 있으면, 그 쿼리만 느린 게 아니라 팀 전체의 분석 환경이 느려지거나 멈출 수도 있음. → 이게 바로 다중 사용자 환경에서는 SQL 성능 고려가 필수인 이유.
▶ 혼자 사용하는 경우
- 느려도 나 혼자만 불편함
- 쿼리를 잠깐 잘못 짜도 시스템 전체에 미치는 영향은 제한적
- 테스트, 실험 중심이라면 느린 쿼리도 일시적 문제로 넘길 수 있음
▶ 여러 사람이 동시에 사용하는 경우 (분석팀, 조직 전체)
- 같은 데이터베이스나 데이터 웨어하우스를 여러 명이 같이 사용하면, 한 사람이 무거운 쿼리를 돌리는 순간 → 다른 사람 쿼리까지 느려짐
- 심한 경우, 전체 시스템 리소스가 고갈돼서 전체 분석 환경이 마비될 수 있음.
- 특히 BI 대시보드, 리포트 등 실시간성 리소스를 공유하는 경우에는 작은 실수 하나가 전체 업무에 피해를 줄 수 있음.
[심화] 왜 무거운 쿼리 하나가 다른 사람 쿼리까지 느리게 만들까?
1. DB 서버는 CPU·메모리·디스크를 함께 씀
데이터베이스는 하나의 서버(혹은 클러스터)에서 모든 사용자 요청을 동시에 처리한다. 이 서버에는 CPU 코어, 메모리, 디스크 I/O 등의 리소스가 한정되어 있는데 누군가 아주 무거운 쿼리(예: 조인 + 정렬 + 집계 + 하위 쿼리)를 돌리면, CPU를 점유하고 메모리를 많이 사용하며 디스크를 계속 읽어야 하기 때문에 → 다른 사람 쿼리가 리소스를 기다려야 한다.
2. 쿼리 실행은 병렬 처리되지만, 리소스는 경쟁해야 함
대부분의 DB는 여러 쿼리를 동시에 병렬로 실행할 수 있다. 하지만 동시에 실행할 수 있다고 해도, 내부적으로는 CPU 코어 수, 쿼리 슬롯 수, 작업 큐 등에서 순서를 기다려야 한다. 그래서 하나의 쿼리가 리소스를 과도하게 잡고 있으면, 다른 쿼리는 느려지거나 대기 상태로 밀릴 수 있다.
3. I/O 병목 현상
무거운 쿼리는 대량의 데이터를 디스크에서 읽거나 정렬해야 하며, 이는 디스크 접근 속도(I/O)에 병목을 만들어서, 다른 쿼리의 데이터 접근도 동시에 느려질 수 있다.
4. 워크로드 관리 정책 한계
BigQuery, Snowflake, Redshift 등 클라우드 DB는 사용량 제한(슬롯, 쿼리 수 등)을 두는 경우가 많다. 이때 한 쿼리가 과도하게 자원을 쓰면, 동시 실행 가능한 쿼리 수가 줄어들고 대기열이 쌓여서 → 전체 쿼리 지연 발생
정리
1) 데이터가 많아질수록 비효율적인 쿼리는 실행 시간이 급격히 증가하거나, 서버 리소스를 과도하게 사용해 실패하거나 시스템에 영향을 줄 수 있고, 2) 여럿이 함께 사용하는 환경에서는 무거운 쿼리 하나가 다른 사람까지 방해할 수 있기 때문에, 성능을 고려해서 SQL을 작성해야 한다!
'데이터 처리 도구 > SQL' 카테고리의 다른 글
| SQL 성능 향상을 위한 공부: 1-2) DBMS와 기억장치의 관계 (0) | 2025.07.02 |
|---|---|
| SQL 성능 향상을 위한 공부: 1-1) DBMS 아키텍처 이해하기 (0) | 2025.07.01 |
| [SQL] MEDIAN() 없이 중앙값 구하기 (0) | 2025.05.22 |
| [SQL] COALESCE( ) 는 합치는 함수다. (NULL이 아닌 값 중에서 처음 등장한 값으로) (0) | 2025.05.21 |
| SQL 실행 순서 (= SQL 논리적 처리 순서) (0) | 2025.04.26 |