TIL 코드카타

bmn.kim·2025년 2월 12일
0

데이터 배우기_SQL

목록 보기
25/25

📌 TIL (Today I Learned) - 2025.02.12

🚀 SQL 성능 최적화: 가독성과 효율을 모두 잡는 방법

코드카타 출처 : https://leetcode.com/problems/queries-quality-and-percentage/?envType=study-plan-v2&envId=top-sql-50

오늘은 SQL 쿼리의 성능 최적화와 가독성 개선 방법에 대해 고민해보았다.
주어진 두 개의 SQL 코드가 동일한 결과를 출력하지만, 성능과 가독성 측면에서 차이가 있었고, 이를 개선하여 최적의 SQL을 도출할 수 있었다.

✅ 1. 기존 코드 분석

첫 번째 쿼리의 문제점

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% 최적화되지는 않음

✅ 2. 최적의 SQL 코드 설계

가독성과 성능을 동시에 잡기 위해 최적의 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;

✅ 3. 개선된 SQL 코드의 장점

1️⃣ 성능 최적화

total_counts에서 COUNT(*)와 SUM(CASE WHEN rating < 3 THEN 1 ELSE 0 END)을 동시에 계산하여 한 번의 GROUP BY 연산으로 해결
기존 코드처럼 COUNT()를 여러 번 수행하지 않음

2️⃣ 가독성 향상

WITH 절을 사용해 quality와 total_counts를 분리하여 논리적으로 정리
핵심 로직이 명확해지고, 새로운 지표를 추가하기 쉬움

3️⃣ NULL 값 안전 처리

rating < 3 데이터가 없는 경우도 IFNULL(cnt_3, 0)을 사용하여 안전하게 처리

🔥 4. 오늘의 배운 점

SQL에서 성능 최적화를 위해 COUNT 연산을 최소화하는 것이 중요하다.

COUNT()를 여러 번 수행하면 쿼리 실행 속도가 느려질 수 있다.
SUM(CASE WHEN 조건 THEN 1 ELSE 0 END) 방식을 사용하면 더 효율적이다.
가독성과 성능은 함께 고려해야 한다.

WITH 절을 활용하면 코드를 논리적으로 정리할 수 있지만, 너무 많으면 오히려 가독성이 떨어질 수 있다.
핵심 연산을 최소화하면서도 직관적인 SQL을 작성하는 것이 중요하다.
LEFT JOIN을 사용할 때 NULL 값을 고려해야 한다.

IFNULL()을 활용해 NULL 값을 적절히 처리하면 데이터 유실을 방지할 수 있다.
✨ 마무리
오늘의 학습을 통해 SQL 최적화의 중요성과 가독성을 유지하는 방법을 배울 수 있었다.
앞으로 복잡한 SQL을 작성할 때, 최소한의 연산으로 최적화된 결과를 얻는 방법을 항상 고민해야겠다.

📍 TIL 작성 끝! 🚀

profile
문과생의 sql 배우기 많은 관심 부탁드립니다

0개의 댓글

관련 채용 정보