쿼리 최적화에 대한 설명과 방법은 개발자 면접에서 자주 나오는 질문 중의 하나!
최적화되지 않은 쿼리는 CPU, 메모리를 불필요하게 소모
서비스를 사용하는 사용자에게 불편함을 제공
-- 비추천
SELECT * FROM SH.Sales;
-- 추천
SELECT s.PROD_ID FROM SH.Sales s;
테이블에서 몇 개의 컬럼만을 조회하는 경우라면, SELECT * 을 사용할 필요가 없다.
필요한 칼럼만 조회
-- 비추천
SELECT s.cust_id, count(s.cust_id)
FROM SH.Sales s
GROUP BY s.cust_id
HAVING s.cust_id != '1660' AND s.cust_id != '2
-- 추천
SELECT s.cust_id, count(s.cust_id)
FROM SH.Sales s
WHERE s.cust_id != '1660' AND s.cust_id != '2'
GROUP BY s.cust_id;
Having 절은 모든 열이 선택된 이후에 필터를 위해 사용된다.
SELECT 문에서는 HAVING절이 불필요
참고: SQL - MIN, MAX, AVG, SUM, HAVING
-- 비추천
SELECT *
FROM TABLE
WHERE COL LIKE '%ABC%'
-- 추천
SELECT *
FROM TABLE
WHERE COL LIKE 'ABC%'
가능하면 와일드카드를 끝에 작성하는 것이 좋다.
LIKE 검색 시, 와일드카드(%)가 시작 부분에 있는 경우, 인덱스를 활용하지 않는다.
-- 비추천
SELECT DISTINCT * FROM SH.Sales s
JOIN SH.Customer c ON s.cust_id = c.cust_id
WHERE c.cust_marital_status = 'single';
-- 추천
SELECT * FROM SH.Sales s
JOIN SH.Customer c ON s.cust_id = c.cust_id
WHERE c.cust_marital_status = 'single';
DISTINCT 가 불필요할 경우에는 사용하지 말자.
UNION 과 DISTINCT 를 같이 사용하지 말자.
Distinct 와 Group By 를 함께 사용하지 말자.
참고: SQL - Join, Union
참고: SQL - TOP, LIMIT, ROWNUM, DISTINCT, COUNT
-- 비추천
SELECT * FROM SH.products p
WHERE p.prod_id = (SELECT s.prod_id FROM SH.sales s WHERE s.cust_id = 100996 AND s.quantity_sold = 1);
-- 추천
SELECT p.* FROM SH.products p, sales s
WHERE p.prod_id = s.prod_id AND s.cust_id = 100996 AND s.quantity_sold = 1;
-- 비추천
SELECT cust_id FROM SH.sales UNION SELECT cust_id FROM customers;
-- 추천
SELECT cust_id FROM SH.sales UNION ALL SELECT cust_id FROM customers;
-- 비추천
SELECT s.* FROM SH.sales s
WHERE s.prod_id = 14 OR s.prod_id = 17;
-- 추천
SELECT s.* FROM SH.sales s
WHERE s.prod_id IN (14, 17);
IN-list에는 상수 또는 쿼리 블록이 실행되는 동안 일정한 값만 포함해야 한다.
IN-list
-- 비추천
SELECT DISTINCT c.country_id, c.country_name
FROM SH.countries c, SH.customers e
WHERE e.country_id = c.country_id;
-- 추천
SELECT c.country_id, c.country_name
FROM SH.countries c
WHERE EXISTS (SELECT 'X' FROM SH.customers e WHERE e.country_id = c.country_id);
WHERE문에서 서브 쿼리의 값을 확인하려는 경우, IN 또는 EXISTS 를 사용할 수 있다.
EXISTS
IN
SELECT *
FROM TABLE
WHERE CONCAT(COL1, ' ') = 'ABC'
암시적 변환
동일한 타입으로 값을 비교하는 것이 좋다.
-- 비추천
SELECT * FROM SH.costs c INNER JOIN SH.products p
ON c.unit_price = p.prod_min_price OR c.unit_price = p.prod_list_price;
-- 추천
SELECT * FROM SH.costs c INNER JOIN SH.products p
ON c.unit_price = p.prod_min_price UNION ALL SELECT * FROM SH.costs c INNER JOIN SH.products p ON c.unit_price = p.prod_list_price;
-- 비추천
SELECT * FROM SH.sales
WHERE EXTRACT (YEAR FROM TO_DATE (time_id, 'DD-MON-RR')) = 2001 AND EXTRACT (MONTH FROM TO_DATE (time_id, 'DD-MON-RR')) = 12;
-- 추천
SELECT * FROM SH.sales
WHERE TRUNC (time_id) BETWEEN TRUNC(TO_DATE('12/01/2001', 'mm/dd/yyyy')) AND TRUNC (TO_DATE ('12/30/2001', 'mm/dd/yyyy'));
-- 비추천
SELECT * FROM SH.sales s WHERE s.cust_id + 10000 < 35000;
-- 추천
SELECT * FROM SH.sales s WHERE s.cust_id < 25000;
참고: [SQL]간단하면서 쉬운 쿼리 최적화 방법
참고: [Database] 쿼리 Query 최적화 및 튜닝 기술