30가지 SQL 최적화 방법
Emily Parker
Product Engineer · Leapcell

1. 적절한 인덱스 선택
팁
쿼리에서 자주 사용되는 열에 적합한 인덱스(단일 열, 복합 인덱스 등)를 생성합니다.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE department_id = 10;
최적화: department_id
에 대한 인덱스 생성:
CREATE INDEX idx_department_id ON employees(department_id);
2. SELECT * 사용하지 않기
팁
반환되는 데이터의 양을 줄이기 위해 필요한 열만 쿼리합니다.
예시
문제 있는 SQL:
SELECT * FROM employees WHERE department_id = 10;
최적화: 필요한 열만 쿼리:
SELECT name FROM employees WHERE department_id = 10;
3. 서브쿼리보다 JOIN 선호
팁
일반적으로 서브쿼리는 JOIN보다 효율성이 떨어집니다.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = 'New York');
최적화: 서브쿼리 대신 JOIN 사용:
SELECT e.name FROM employees e JOIN departments d ON e.department_id = d.id WHERE d.location = 'New York';
4. EXPLAIN을 사용하여 쿼리 분석
팁
EXPLAIN
또는 EXPLAIN ANALYZE
를 사용하여 SQL 쿼리의 실행 계획을 보고 성능 병목 현상을 식별합니다.
예시
EXPLAIN SELECT name FROM employees WHERE department_id = 10;
5. 불필요한 ORDER BY 작업 피하기
팁
ORDER BY
는 특히 큰 데이터셋에서 상당한 리소스를 소비합니다. 정렬이 필요한 경우에만 사용하십시오.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE department_id = 10 ORDER BY hire_date;
최적화: 정렬이 필요하지 않은 경우 ORDER BY
제거.
6. LIMIT을 사용하여 페이지네이션 쿼리 최적화
팁
페이지네이션의 경우 LIMIT
를 사용하십시오. 큰 오프셋이 있는 쿼리의 경우 인덱스 또는 캐싱을 사용하여 최적화하십시오.
예시
문제 있는 SQL:
SELECT name FROM employees ORDER BY hire_date LIMIT 100000, 10;
최적화: 기본 키 또는 인덱스를 사용하여 페이지네이션 성능 향상:
SELECT name FROM employees WHERE id > 100000 ORDER BY hire_date LIMIT 10;
7. WHERE 절에서 함수 사용하지 않기
팁
함수 호출은 인덱스 사용을 방지합니다. 가능한 경우 피하십시오.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE YEAR(hire_date) = 2023;
최적화: 대신 범위 쿼리 사용:
SELECT name FROM employees WHERE hire_date BETWEEN '2023-01-01' AND '2023-12-31';
8. 복합 인덱스에 적절한 순서 선택
팁
복합 인덱스에서는 선택성이 높은 열을 먼저 배치하십시오.
예시
다음 쿼리의 경우:
SELECT * FROM employees WHERE department_id = 10 AND status = 'active';
더 나은 선택성을 위해 status
를 먼저 사용하여 인덱스를 생성하십시오:
CREATE INDEX idx_status_department ON employees(status, department_id);
9. 단일 삽입 대신 배치 삽입 사용
팁
배치 삽입은 I/O 및 잠금 오버헤드를 크게 줄입니다.
예시
문제 있는 SQL: 레코드를 하나씩 삽입:
INSERT INTO employees (name, department_id) VALUES ('John', 10);
최적화: 배치 삽입 사용:
INSERT INTO employees (name, department_id) VALUES ('John', 10), ('Alice', 20), ('Bob', 30);
10. NOT IN 사용 피하기
팁
NOT IN
은 성능이 좋지 않습니다. NOT EXISTS
또는 LEFT JOIN
으로 대체하십시오.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE department_id NOT IN (SELECT id FROM departments);
최적화: LEFT JOIN
사용:
SELECT e.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id WHERE d.id IS NULL;
11. 중복 DISTINCT 피하기
팁
중복 데이터를 제거해야 하는 경우에만 DISTINCT
를 사용하십시오.
예시
문제 있는 SQL:
SELECT DISTINCT name FROM employees WHERE department_id = 10;
최적화: 중복이 불필요한 경우 DISTINCT
제거.
12. 적절한 Join 유형 사용
팁
모든 데이터가 필요한 경우가 아니면 INNER JOIN
을 선호하십시오. 불필요하게 LEFT JOIN
또는 RIGHT JOIN
을 피하십시오.
예시
문제 있는 SQL:
SELECT e.name, d.name FROM employees e LEFT JOIN departments d ON e.department_id = d.id;
최적화: INNER JOIN
사용:
SELECT e.name, d.name FROM employees e INNER JOIN departments d ON e.department_id = d.id;
13. 테이블 파티셔닝 사용
팁
쿼리 성능을 향상시키기 위해 큰 테이블을 파티셔닝하십시오.
예시
CREATE TABLE employees ( id INT, name VARCHAR(50), hire_date DATE ) PARTITION BY RANGE (YEAR(hire_date)) ( PARTITION p2020 VALUES LESS THAN (2021), PARTITION p2021 VALUES LESS THAN (2022) );
14. GROUP BY 쿼리 최적화
팁
인덱스를 사용하여 GROUP BY
쿼리를 최적화하십시오.
예시
SELECT department_id, COUNT(*) FROM employees GROUP BY department_id;
15. IN 사용 최적화
팁
큰 IN
작업의 경우 데이터를 임시 테이블에 저장하고 대신 JOIN
을 사용하십시오.
예시
문제 있는 SQL:
SELECT name FROM employees WHERE department_id IN (1, 2, 3, 4, 5);
최적화: 임시 테이블에 ID 저장:
CREATE TEMPORARY TABLE temp_ids (id INT); INSERT INTO temp_ids (id) VALUES (1), (2), (3), (4), (5); SELECT e.name FROM employees e JOIN temp_ids t ON e.department_id = t.id;
16. 복잡한 뷰 사용 제한
팁
뷰는 복잡성과 성능 오버헤드를 추가합니다. 복잡한 쿼리에는 직접 SQL을 사용하십시오.
예시
복잡한 뷰 쿼리를 최적화된 SQL 문으로 바꾸십시오.
17. 잠금 사용 최적화
팁
전체 테이블 잠금을 피하기 위해 적절한 잠금 메커니즘을 사용하십시오(예: LOCK IN SHARE MODE
).
예시
SELECT * FROM employees WHERE id = 10 FOR UPDATE;
18. INSERT INTO SELECT 문 최적화
팁
성능을 향상시키기 위해 INSERT INTO SELECT
문에서 인덱스를 사용하십시오.
예시
INSERT INTO employees_backup (id, name) SELECT id, name FROM employees WHERE hire_date < '2020-01-01';
19. 연결 풀 사용
팁
잦은 데이터베이스 작업의 경우 효율성을 향상시키기 위해 연결 풀을 사용하십시오.
예시
애플리케이션 수준에서 연결 풀을 구성하십시오.
20. 메모리 매개변수 모니터링 및 조정
팁
쿼리 요구에 맞게 메모리 설정(예: MySQL의 innodb_buffer_pool_size
)을 조정하십시오.
예시
쿼리 메모리 요구 사항에 따라 구성을 조정하십시오.
21. 분산 쿼리 최적화
팁
분산 데이터베이스 환경에서는 노드 간 데이터 전송을 최소화하고 쿼리 계획을 최적화하십시오.
예시
문제 있는 SQL:
SELECT e.name, d.name FROM employees e JOIN departments d ON e.department_id = d.id WHERE e.location = 'New York';
최적화: 노드 간 데이터 전송을 피하기 위해 글로벌 집계 전에 로컬 노드에서 위치 관련 데이터를 처리하십시오.
22. 다중 열 인덱스 및 인덱스 병합
팁
여러 열을 쿼리할 때는 가능한 경우 복합 인덱스를 사용하십시오. 그렇지 않으면 데이터베이스가 인덱스 병합을 시도할 수 있습니다.
예시
문제 있는 SQL:
SELECT * FROM orders WHERE customer_id = 10 AND product_id = 5;
최적화: 더 나은 성능을 위해 customer_id
및 product_id
에 대한 인덱스를 결합하십시오. EXPLAIN
을 사용하여 인덱스 병합이 사용되는지 확인하십시오.
23. CUBE 및 ROLLUP으로 다차원 분석 최적화
팁
여러 GROUP BY
쿼리를 줄여 다차원 집계에 CUBE
및 ROLLUP
을 사용하십시오.
예시
문제 있는 SQL: 여러 GROUP BY
쿼리.
SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id; SELECT region, SUM(sales) FROM sales_data GROUP BY region;
최적화: 여러 수준에서 집계하기 위해 ROLLUP
사용:
SELECT department_id, region, SUM(sales) FROM sales_data GROUP BY department_id, region WITH ROLLUP;
24. 복잡한 분석 쿼리에 창 함수 사용
팁
창 함수(예: ROW_NUMBER()
, RANK()
, LAG()
, LEAD()
)는 자체 조인 또는 서브쿼리의 필요성을 줄여 복잡한 분석을 단순화합니다.
예시
문제 있는 SQL: 이전 레코드를 가져오기 위해 자체 조인.
SELECT a.*, (SELECT sales FROM sales_data b WHERE b.id = a.id - 1) AS previous_sales FROM sales_data a;
최적화: 창 함수 사용:
SELECT id, sales, LAG(sales, 1) OVER (ORDER BY id) AS previous_sales FROM sales_data;
25. 큰 테이블에 대한 파티션 정리
팁
매우 큰 테이블의 데이터 스캔 범위를 제한하려면 파티션 정리를 사용하십시오.
예시
문제 있는 SQL:
SELECT * FROM transactions WHERE transaction_date BETWEEN '2023-01-01' AND '2023-01-31';
최적화: 날짜별로 테이블을 파티셔닝하고 정리를 활용하십시오.
CREATE TABLE transactions ( id INT, amount DECIMAL(10, 2), transaction_date DATE ) PARTITION BY RANGE (YEAR(transaction_date)) ( PARTITION p2023 VALUES LESS THAN (2024) );
26. 임시 테이블 사용 최소화
팁
복잡한 쿼리에서 임시 테이블 사용을 줄이십시오. 이는 디스크 I/O를 증가시키고 성능에 영향을 미칩니다.
예시
문제 있는 SQL: 중간 결과를 저장하기 위해 임시 테이블 사용.
CREATE TEMPORARY TABLE temp_sales AS SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id;
최적화: 서브쿼리 또는 공통 테이블 표현식(CTE) 사용:
WITH temp_sales AS ( SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id ) SELECT * FROM temp_sales;
27. 병렬 쿼리 최적화
팁
효율성을 향상시키기 위해 큰 데이터셋에 대한 병렬 쿼리 실행을 활용하십시오.
예시
문제 있는 SQL: 병렬 처리가 없는 큰 데이터 스캔.
SELECT SUM(sales) FROM sales_data;
최적화: 병렬 쿼리 실행 활성화:
ALTER SESSION ENABLE PARALLEL QUERY; SELECT /*+ PARALLEL(sales_data, 4) */ SUM(sales) FROM sales_data;
28. 구체화된 뷰로 복잡한 쿼리 가속화
팁
복잡한 집계 쿼리의 경우 미리 계산된 결과를 저장하기 위해 구체화된 뷰를 사용하십시오.
예시
문제 있는 SQL: 성능 병목 현상이 있는 복잡한 집계 쿼리.
SELECT department_id, SUM(sales) FROM sales_data GROUP BY department_id;
최적화: 구체화된 뷰 생성:
CREATE MATERIALIZED VIEW mv_sales_data AS SELECT department_id, SUM(sales) AS total_sales FROM sales_data GROUP BY department_id;
29. 동시 쿼리를 최적화하기 위해 잠금 경합 방지
팁
높은 동시성 환경에서는 적절한 잠금 메커니즘을 사용하여 테이블 또는 행 잠금을 피하십시오.
예시
문제 있는 SQL: 높은 동시성에서 성능 저하를 일으키는 테이블 잠금.
SELECT * FROM orders WHERE status = 'pending' FOR UPDATE;
최적화: 특정 행만 잠금:
SELECT * FROM orders WHERE order_id = 123 FOR UPDATE;
30. 잠금 시간을 줄여 트랜잭션 최적화
팁
장기 실행 트랜잭션의 경우 잠금 시간을 최소화하고 잠금 범위를 줄이십시오.
예시
문제 있는 SQL: 트랜잭션 중에 테이블을 잠그는 대규모 데이터 작업.
BEGIN; UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; UPDATE accounts SET balance = balance + 100 WHERE account_id = 2; COMMIT;
최적화: 더 작은 트랜잭션으로 분할하거나 잠금 시간을 줄이십시오.
BEGIN; UPDATE accounts SET balance = balance - 100 WHERE account_id = 1; COMMIT; BEGIN; UPDATE accounts SET balance = balance + 100 WHERE account_id = 2; COMMIT;
SQL 쿼리 최적화는 예술이자 과학입니다.
위에 설명된 기술은 쿼리 성능 향상을 위한 강력한 기반을 제공하지만 진정한 숙달의 열쇠는 끊임없는 실험과 적응에 있습니다.
모든 데이터베이스는 고유합니다. 한 시나리오에 적합한 것이 다른 시나리오에는 적합하지 않을 수 있습니다. 항상 쿼리를 분석, 테스트 및 개선하여 자체 최적화를 구축하십시오.
클라우드에 백엔드 프로젝트를 배포하는 최고의 선택, Leapcell입니다.
Leapcell은 웹 호스팅, 비동기 작업 및 Redis를 위한 차세대 서버리스 플랫폼입니다.
다국어 지원
- Node.js, Python, Go 또는 Rust로 개발하십시오.
무제한 프로젝트를 무료로 배포
- 사용량에 대해서만 지불하십시오. 요청 없음, 요금 없음.
탁월한 비용 효율성
- 유휴 요금 없이 사용한 만큼 지불하십시오.
- 예: $25는 평균 응답 시간 60ms에서 694만 건의 요청을 지원합니다.
간소화된 개발자 경험
- 간편한 설정을 위한 직관적인 UI.
- 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 실행 가능한 통찰력을 위한 실시간 메트릭 및 로깅.
손쉬운 확장성 및 고성능
- 고도의 동시성을 쉽게 처리할 수 있는 자동 확장.
- 운영 오버헤드 제로 — 구축에만 집중하십시오.
설명서에서 자세히 알아보십시오!
X에서 팔로우하세요: @LeapcellHQ