DB

[DB] SQL 쿼리 튜닝 시 고려사항

테런 2023. 9. 18. 01:01
  • SQL 쿼리 튜닝 시 고려사항
쿼리 튜닝(query tuning)은 데이터베이스 성능을 최적화하기 위해 SQL 쿼리를 개선하는 과정입니다. 데이터베이스 성능을 향상시키기 위해 쿼리를 튜닝할 때 고려해야 할 주요 사항은 다음과 같습니다.

1. 실행 계획 분석: 데이터베이스 관리 시스템(DBMS)이 생성하는 실행 계획을 분석합니다. 이를 통해 쿼리가 어떻게 실행되는지 이해할 수 있습니다.

2. 인덱스 활용: 인덱스를 적절하게 활용하여 데이터베이스 접근 속도를 향상시킬 수 있습니다. 쿼리에서 사용되는 조건절과 조인 조건에 인덱스를 생성하거나 적절한 인덱스를 활용하는지 확인하세요.

3. 조인 최적화: 조인 연산을 최적화하여 쿼리의 성능을 개선합니다. 필요한 경우 INNER JOIN, LEFT JOIN, RIGHT JOIN 등 다양한 조인 유형을 고려하세요.

4. 서브쿼리 최적화: 서브쿼리를 사용할 때 성능에 미치는 영향을 고려하고, 필요한 경우 서브쿼리를 조인이나 다른 방법으로 대체할 수 있습니다.

5. 필요한 컬럼 선택: SELECT 문에서 실제로 필요한 컬럼만 선택하도록 하여 불필요한 데이터를 검색하는 것을 피합니다. 이는 네트워크 및 메모리 사용량을 줄여 성능을 개선할 수 있습니다.

6. 검색 조건 최적화: WHERE 절의 검색 조건을 최적화하여 데이터베이스에서 필요한 데이터만 검색하도록 합니다. 이때 인덱스를 활용하는 조건을 잘 선택하고 불필요한 조건을 제거합니다.

7. 서버 자원 관리: 데이터베이스 서버의 자원(CPU, 메모리, 디스크 공간) 사용을 모니터링하고 관리합니다. 쿼리가 서버 자원을 과도하게 사용하지 않도록 합니다.

8. 통계 업데이트: 데이터베이스 통계 정보를 정기적으로 업데이트하여 실행 계획을 최적화합니다.

9. 잠금 관리: 트랜잭션 격리 수준을 고려하여 데이터베이스 잠금을 관리하고 데드락을 방지합니다.

10. 캐싱 활용: 쿼리 결과를 캐시하여 이전에 실행된 동일한 쿼리에 대한 응답 시간을 줄입니다.

11. 하드웨어 업그레이드: 성능 문제를 해결하기 위해 하드웨어 업그레이드를 고려할 수 있습니다. 예를 들어, 더 빠른 CPU, 더 많은 메모리, 빠른 디스크 등을 사용할 수 있습니다.

12. 모니터링과 프로파일링: 쿼리의 성능을 지속적으로 모니터링하고 프로파일링하여 성능 문제를 식별하고 해결합니다.

13. 테스트 환경: 쿼리 튜닝 전에 테스트 환경에서 변경 사항을 검증합니다. 실제 운영 환경에서 변경을 수행하기 전에 예상되는 영향을 확인하세요.

쿼리 튜닝은 데이터베이스 성능 최적화의 중요한 부분이며, 성능 문제를 해결하고 데이터베이스의 효율성을 향상시키는 데 도움이 됩니다. 따라서 신중하게 계획하고 실행해야 합니다.

 

 

  • 인덱스 활용 예시
SQL 쿼리 튜닝에서 인덱스 활용은 성능을 크게 향상시킬 수 있는 중요한 부분입니다. 아래는 간단한 예시를 통해 인덱스를 활용하는 방법을 보여줍니다.

가정: 하나의 테이블 "employees"가 있으며, 이 테이블에는 다음과 같은 컬럼이 있습니다.
- employee_id (고유 식별자, 기본 키)
- first_name (직원 이름)
- last_name (직원 성)
- department_id (부서 식별자)
- hire_date (고용일)

직원 테이블에서 특정 부서의 모든 직원을 검색하는 쿼리를 고려해 봅시다.

1. 인덱스가 없는 경우
SELECT * FROM employees WHERE department_id = 10;​

 

2. 인덱스를 사용하는 경우
-- department_id 컬럼에 인덱스가 있는 경우
CREATE INDEX idx_department_id ON employees(department_id);
-- 이제 인덱스를 활용하여 쿼리 실행
SELECT * FROM employees WHERE department_id = 10;​

 

* 인덱스를 사용하는 경우의 이점
인덱스를 사용하면 데이터베이스는 직원 테이블의 모든 행을 스캔하는 대신, 인덱스를 사용하여 department_id가 10인 행만 검색합니다. 이로 인해 검색 속도가 향상되며, 대규모 데이터베이스에서도 빠른 응답을 얻을 수 있습니다.

* 인덱스를 사용할 때 주의할 점
- 인덱스를 많이 생성하면 데이터 삽입, 갱신, 삭제 작업의 성능에 영향을 미칠 수 있으므로 필요한 인덱스만 생성해야 합니다.
- 인덱스 컬럼을 선택할 때 쿼리에 자주 사용되는 컬럼을 우선적으로 고려하세요.
- 조인 조건, 정렬, 그룹화 등 다양한 쿼리에서 인덱스를 활용할 수 있습니다. 필요한 경우 다른 인덱스를 생성하세요. 인덱스는 데이터베이스 성능 향상에 중요한 역할을 하며, 데이터베이스 설계와 쿼리 튜닝 과정에서 올바르게 활용하는 것이 중요합니다.

 

 

  • 조인 최적화 예시
SQL 쿼리 튜닝에서 적절한 JOIN을 선택하는 것은 성능 개선에 중요합니다. JOIN은 테이블 간 데이터 연결에 사용되며, 다음은 쿼리 튜닝에서 적절한 JOIN을 선택하는 예시입니다.

두 개의 테이블 "orders"와 "customers"가 있습니다. "orders" 테이블에는 주문 정보가 저장되어 있고, "customers" 테이블에는 고객 정보가 저장되어 있습니다. 각 테이블의 구조는 다음과 같습니다.

* orders 테이블
- order_id (주문 식별자, 기본 키)
- customer_id (주문한 고객의 식별자)
- order_date (주문일)
- total_amount (주문 총액)

* customers 테이블
- customer_id (고객 식별자, 기본 키)
- first_name (고객 이름)
- last_name (고객 성)
- email (고객 이메일)

이제 주어진 고객의 이름과 해당 고객이 주문한 주문의 총액을 조회하는 쿼리를 고려해 봅시다.

1. INNER JOIN 사용
SELECT c.first_name, c.last_name, SUM(o.total_amount) AS total_order_amount
FROM customers c
INNER JOIN orders o ON c.customer_id = o.customer_id
WHERE c.first_name = 'John'
GROUP BY c.first_name, c.last_name;​

2. LEFT JOIN 사용

SELECT c.first_name, c.last_name, SUM(o.total_amount) AS total_order_amount
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE c.first_name = 'John'
GROUP BY c.first_name, c.last_name;

* INNER JOIN
- INNER JOIN은 두 테이블 간에 일치하는 행만 반환합니다. 즉, 주문을 한 고객만 결과에 포함됩니다. - 만약 고객이 주문을 한 번도 하지 않았다면 결과에 나타나지 않습니다.

* LEFT JOIN
- LEFT JOIN은 왼쪽 테이블(여기서는 "customers")의 모든 행을 반환하며, 오른쪽 테이블("orders")의 일치하는 행이 없으면 NULL 값을 반환합니다.

- LEFT JOIN을 사용하면 주문을 한 번도 하지 않은 고객도 결과에 나타날 수 있습니다. 어떤 JOIN을 선택할지는 비즈니스 요구사항에 따라 다릅니다. INNER JOIN은 주문을 한 고객만 필요한 경우에 유용하며, LEFT JOIN은 모든 고객을 포함하고 싶을 때 사용될 수 있습니다. 따라서 쿼리의 목적과 필요에 따라 JOIN 유형을 선택해야 합니다.

 

 

  • 서브쿼리 최적화 예시
SQL 쿼리 튜닝에서 서브쿼리 최적화는 성능 향상을 위해 중요한 부분입니다. 서브쿼리를 최적화하려면 몇 가지 전략을 사용할 수 있습니다. 아래는 서브쿼리 최적화의 예시입니다.

주문 정보를 저장하는 "orders" 테이블과 주문에 대한 특정 조건을 만족하는 주문을 찾는 "order_items" 테이블이 있다고 가정합니다.

* orders 테이블
- order_id (주문 식별자, 기본 키)
- customer_id (주문한 고객의 식별자)
- order_date (주문일)
- total_amount (주문 총액)

* order_items 테이블
- order_item_id (주문 항목 식별자, 기본 키)
- order_id (주문 식별자)
- product_id (상품 식별자)
- quantity (주문된 수량)

이제 주어진 조건에 따라 주문 정보를 검색하는 서브쿼리를 최적화하는 예시를 살펴보겠습니다.

1. 서브쿼리 사용
SELECT order_id, customer_id, order_date, total_amount
FROM orders
WHERE order_id IN (
  SELECT order_id
  FROM order_items
  WHERE product_id = 101
);​

2. JOIN 사용

SELECT o.order_id, o.customer_id, o.order_date, o.total_amount
FROM orders o
INNER JOIN order_items oi ON o.order_id = oi.order_id
WHERE oi.product_id = 101;

 

* 서브쿼리 사용
- 첫 번째 쿼리는 서브쿼리를 사용하여 주문 항목 테이블에서 조건을 검색하고 해당하는 주문을 찾습니다.
- 서브쿼리를 사용하면 두 개의 서로 다른 쿼리가 실행됩니다. 먼저 주문 항목을 검색하고, 그 결과를 사용하여 주문을 검색합니다.

* JOIN 사용
- 두 번째 쿼리는 INNER JOIN을 사용하여 "orders"와 "order_items" 테이블을 조인합니다. 조인 조건은 주문 식별자인 "order_id"가 일치해야 합니다.
- JOIN을 사용하면 하나의 쿼리만 실행되므로 서브쿼리를 사용하는 것보다 성능상 이점이 있을 수 있습니다. 일반적으로 JOIN을 사용하는 것이 성능상 더 효율적일 수 있습니다. 서브쿼리는 필요한 경우에만 사용해야 하며, 대부분의 경우 JOIN을 활용하여 데이터를 효율적으로 추출할 수 있습니다. JOIN을 사용하면 데이터베이스 엔진이 최적의 실행 계획을 선택할 기회가 더 많아집니다.