코드카타 출처 : https://leetcode.com/problems/queries-quality-and-percentage/?envType=study-plan-v2&envId=top-sql-50
오늘은 SQL 쿼리의 성능 최적화와 가독성 개선 방법에 대해 고민해보았다.
주어진 두 개의 SQL 코드가 동일한 결과를 출력하지만, 성능과 가독성 측면에서 차이가 있었고, 이를 개선하여 최적의 SQL을 도출할 수 있었다.
WITH quality AS
(
SELECT
query_name,
round(sum(rating / position) / count(query_name),2) as quality
FROM Queries q
GROUP BY 1
),
poor_query_percentage AS
(SELECT
query_name,
Round(CAST(SUM(CASE WHEN rating < 3 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(query_name) * 100,2) AS poor_query_percentage
FROM Queries
GROUP BY query_name)
SELECT
q.query_name,
q.quality,
p.poor_query_percentage
FROM quality q
JOIN poor_query_percentage p
ON q.query_name = p.query_name
COUNT()를 여러 번 수행하여 불필요한 연산 발생
CAST(... AS FLOAT)가 필요 이상으로 사용됨
JOIN을 사용하여 데이터를 결합하는 방식이지만, 성능 최적화는 부족
WITH aa AS
(SELECT query_name,
count(query_name) as cnt_total
FROM Queries
GROUP BY 1),
bb AS
(SELECT query_name,
count(query_name) as cnt_3
FROM Queries
WHERE rating < 3
GROUP BY 1),
cc AS
(
SELECT aa.query_name,
round(cnt_3/cnt_total*100,2) as poor_query_percentage
FROM aa
LEFT JOIN bb
ON aa.query_name = bb.query_name
GROUP BY 1
)
SELECT t.query_name,
t.quality,
cc.poor_query_percentage
FROM
(SELECT query_name,
round(sum(rating/position)/count(query_name),2) as quality
FROM queries
GROUP BY 1
)t
LEFT JOIN cc
ON t.query_name = cc.query_name
WITH 절을 여러 번 사용하여 가독성이 다소 복잡
COUNT() 연산을 줄였지만, LEFT JOIN이 필요하여 성능적으로 100% 최적화되지는 않음
가독성과 성능을 동시에 잡기 위해 최적의 SQL을 설계했다.
WITH total_counts AS (
SELECT
query_name,
COUNT(*) AS cnt_total,
SUM(CASE WHEN rating < 3 THEN 1 ELSE 0 END) AS cnt_3
FROM Queries
GROUP BY query_name
),
quality AS (
SELECT
query_name,
ROUND(SUM(rating / position) / COUNT(*), 2) AS quality
FROM Queries
GROUP BY query_name
)
SELECT
q.query_name,
q.quality,
ROUND(IFNULL(tc.cnt_3, 0) / tc.cnt_total * 100, 2) AS poor_query_percentage
FROM quality q
LEFT JOIN total_counts tc
ON q.query_name = tc.query_name;
total_counts에서 COUNT(*)와 SUM(CASE WHEN rating < 3 THEN 1 ELSE 0 END)을 동시에 계산하여 한 번의 GROUP BY 연산으로 해결
기존 코드처럼 COUNT()를 여러 번 수행하지 않음
WITH 절을 사용해 quality와 total_counts를 분리하여 논리적으로 정리
핵심 로직이 명확해지고, 새로운 지표를 추가하기 쉬움
rating < 3 데이터가 없는 경우도 IFNULL(cnt_3, 0)을 사용하여 안전하게 처리
SQL에서 성능 최적화를 위해 COUNT 연산을 최소화하는 것이 중요하다.
COUNT()를 여러 번 수행하면 쿼리 실행 속도가 느려질 수 있다.
SUM(CASE WHEN 조건 THEN 1 ELSE 0 END) 방식을 사용하면 더 효율적이다.
가독성과 성능은 함께 고려해야 한다.
WITH 절을 활용하면 코드를 논리적으로 정리할 수 있지만, 너무 많으면 오히려 가독성이 떨어질 수 있다.
핵심 연산을 최소화하면서도 직관적인 SQL을 작성하는 것이 중요하다.
LEFT JOIN을 사용할 때 NULL 값을 고려해야 한다.
IFNULL()을 활용해 NULL 값을 적절히 처리하면 데이터 유실을 방지할 수 있다.
✨ 마무리
오늘의 학습을 통해 SQL 최적화의 중요성과 가독성을 유지하는 방법을 배울 수 있었다.
앞으로 복잡한 SQL을 작성할 때, 최소한의 연산으로 최적화된 결과를 얻는 방법을 항상 고민해야겠다.
📍 TIL 작성 끝! 🚀