Coding Challenges/LeetCode

[SQL50] 1148. Article Views I

기록해연 2025. 2. 10. 10:05

난이도: EASY

 

문제

더보기

Table: Views
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| article_id    | int     |
| author_id     | int     |
| viewer_id     | int     |
| view_date     | date    |
+---------------+---------+
There is no primary key (column with unique values) for this table, the table may have duplicate rows.
Each row of this table indicates that some viewer viewed an article (written by some author) on some date. 
Note that equal author_id and viewer_id indicate the same person.
 
Write a solution to find all the authors that viewed at least one of their own articles.
Return the result table sorted by id in ascending order.
The result format is in the following example.

Example 1:
Input: 
Views table:
+------------+-----------+-----------+------------+
| article_id | author_id | viewer_id | view_date  |
+------------+-----------+-----------+------------+
| 1          | 3         | 5         | 2019-08-01 |
| 1          | 3         | 6         | 2019-08-02 |
| 2          | 7         | 7         | 2019-08-01 |
| 2          | 7         | 6         | 2019-08-02 |
| 4          | 7         | 1         | 2019-07-22 |
| 3          | 4         | 4         | 2019-07-21 |
| 3          | 4         | 4         | 2019-07-21 |
+------------+-----------+-----------+------------+
Output: 
+------+
| id   |
+------+
| 4    |
| 7    |
+------+


 

주요 함수

DISTINCT : 중복되는 컬럼 제거

 

나의 최종 제출 답안:

SELECT DISTINCT author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY id

 

 


 

chatGPT에게 더 간단하고 효율적이게 수정해달라고 요청한 답안:

 

🔥 1️⃣ GROUP BY를 사용 (더 나은 방법)

SELECT id, MIN(name) AS name FROM 테이블명 GROUP BY id;
/* 이용하여 제출해본 답안 */
SELECT MIN(author_id) AS id 
FROM Views 
WHERE author_id = viewer_id
GROUP BY author_id
ORDER BY id;

✅ GROUP BY는 중복된 id 값 중 하나를 선택하면서 성능을 향상시킬 수 있습니다.
✅ MIN(name)을 사용하면 중복된 id 중 가장 작은 name을 가져옴.
✅ DISTINCT보다 성능이 더 나을 수 있음 (GROUP BY는 최적화가 잘 됨).

 


🔥 2️⃣ ROW_NUMBER()를 활용한 방법 (특정 기준으로 정렬)

SELECT id
FROM (
    SELECT author_id AS id, ROW_NUMBER() OVER (PARTITION BY author_id ORDER BY author_id) AS rn
    FROM Views
    WHERE author_id = viewer_id
) WHERE rn = 1
ORDER BY id ASC;
 

✅ ROW_NUMBER()를 사용하면 특정 정렬 기준에 따라 중복을 제거할 수 있음.
✅ ORDER BY name ASC를 설정하여 원하는 값을 가져올 수 있음.
대량의 데이터에서는 성능이 더 좋음 (인덱스를 잘 활용할 경우).


🔥 3️⃣ DISTINCT ON (PostgreSQL에서 사용 가능)

💡 오라클에서는 지원되지 않지만, PostgreSQL에서 사용 가능!

SELECT DISTINCT ON (author_id) author_id AS id
FROM Views
WHERE author_id = viewer_id
ORDER BY author_id;
 

✅ DISTINCT ON (id)는 같은 id 값이 여러 개 있을 때, 가장 첫 번째 행을 반환
✅ ORDER BY를 사용하여 정렬된 첫 번째 행을 선택 가능
PostgreSQL에서만 사용 가능 (오라클에서는 지원되지 않음)

 


어떤 방법이 가장 효율적인가요?

방법설명성능

방법 설명 성능
DISTINCT 가장 간단하지만, 성능이 떨어질 수도 있음 🟡 보통
GROUP BY DISTINCT보다 더 빠를 수 있음 🟢 빠름
ROW_NUMBER() 특정 정렬 기준을 유지하면서 중복 제거 가능 🟢 빠름
DISTINCT ON PostgreSQL 전용 (가장 빠름) 🔵 매우 빠름

🚀 결론

가장 추천하는 방법: GROUP BY, ROW_NUMBER()
✅ DISTINCT는 간단하지만, 데이터가 많으면 최적화가 어렵고 느릴 수 있음
인덱스를 활용할 경우 ROW_NUMBER()가 가장 효율적일 가능성이 높음!

 



+ 추가질문

 

🔥 왜 DISTINCT는 성능이 떨어질까?

DISTINCT는 중복 제거를 위해 추가적인 연산이 필요하기 때문에 성능이 떨어질 수 있습니다.
특히 데이터가 많거나, 컬럼 개수가 많을 경우 성능 저하가 심해질 수 있습니다.

 

1️⃣ DISTINCT의 내부 동작 방식

SELECT DISTINCT id FROM Customer;
 

오라클이 DISTINCT를 실행할 때 다음과 같은 단계를 수행합니다:

 

1️⃣ 데이터를 읽음 (Full Table Scan 가능성 있음)
2️⃣ 정렬(SORT) 수행 → 중복된 값을 찾기 위해 정렬(SORT UNIQUE) 과정 필요
3️⃣ 정렬된 데이터에서 중복된 행을 제거
4️⃣ 최종 결과 반환

👉 즉, 정렬(SORT) 과정이 필수적이므로 성능이 떨어질 가능성이 큼!
👉 인덱스를 사용하지 않으면 Full Table Scan이 발생할 수도 있음!