안내
본 문서는 블로그의 운영자인 본인이 Stackoverflow에 올린 답변을 정리한 글입니다.
Stackoverflow URL
http://stackoverflow.com/questions/20209350/mysql-select-row-by-comparing-two-columns/21322502
SQLFiddle URL
http://www.sqlfiddle.com/#!2/9a9fa/1
질문
다음과 같은 messages 테이블이 있다.
mysql> SELECT * FROM messages;
+---------------+-----------------+----------+---------------------+
| sender_userid | receiver_userid | msg_body | date_sent |
+---------------+-----------------+----------+---------------------+
| user1 | user2 | msg1 | 2014-12-01 00:00:00 |
| user2 | user1 | msg2 | 2014-12-02 00:00:00 |
| user1 | user2 | msg3 | 2014-12-03 00:00:00 |
| user2 | user1 | msg4 | 2014-12-04 00:00:00 |
+---------------+-----------------+----------+---------------------+
4 rows in set (0.00 sec)
sender_userid가 receiver_userid에게 보낸 메시지가 저장된 테이블이다. user1에 대해서 송신, 수신과 상관없이 가장 최근의 메시지 1개를 조회하려고 한다. 어떻게 하는 것이 좋은가? 내가 시도한 SQL은 다음과 같다.
SELECT sender_userid, receiver_userid, msg_body, date_sent
FROM (
SELECT sender_userid, receiver_userid, msg_body, date_sent
FROM messages
WHERE (receiver_userid = 'user1' OR sender_userid = 'user1')
ORDER BY date_sent DESC
) AS MSG
GROUP BY receiver_userid;
+---------------+-----------------+----------+---------------------+
| sender_userid | receiver_userid | msg_body | date_sent |
+---------------+-----------------+----------+---------------------+
| user2 | user1 | msg4 | 2014-12-04 00:00:00 |
| user1 | user2 | msg3 | 2014-12-03 00:00:00 |
+---------------+-----------------+----------+---------------------+
2 rows in set (0.00 sec)
답변
질문자가 질문한 내용, 시도한 SQL, 질문자가 채택한 답변이 서로 달라서 이해하기 어려웠던 질문이다. 아래의 SQL을 이용하면 질문자가 의도한 결과를 쉽게 얻을 수 있다.
SELECT 'user1' AS my_id, sender_userid, receiver_userid, date_sent
FROM messages
WHERE (receiver_userid='user1' OR sender_userid='user1')
ORDER BY date_sent DESC
LIMIT 1;
+-------+---------------+-----------------+---------------------+
| my_id | sender_userid | receiver_userid | date_sent |
+-------+---------------+-----------------+---------------------+
| user1 | user2 | user1 | 2014-12-04 00:00:00 |
+-------+---------------+-----------------+---------------------+
1 row in set (0.00 sec)
질의 개선 (MySQL 5.0 이하인 경우)
서로 다른 컬럼에 대해 OR 연산을 수행하는 경우, 각각의 컬럼에 INDEX되었더라도 INDEX를 활용할 수가 없기 때문에 위의 질의는 속도가 느리다. 성능 개선을 위해서는 귀찮더라도 다음과 같이 UNION을 사용하여 OR를 제거해 주는 것이 좋다.
SELECT *
FROM (
(
SELECT 'user1' AS my_id, sender_userid, receiver_userid, date_sent
FROM messages
WHERE receiver_userid='user1'
ORDER BY date_sent DESC
LIMIT 1
)
UNION ALL
(
SELECT 'user1' AS my_id, sender_userid, receiver_userid, date_sent
FROM messages
WHERE sender_userid='user1'
ORDER BY date_sent DESC
LIMIT 1
)
) x
ORDER BY date_sent DESC
LIMIT 1;
+-------+---------------+-----------------+---------------------+
| my_id | sender_userid | receiver_userid | date_sent |
+-------+---------------+-----------------+---------------------+
| user1 | user2 | user1 | 2014-12-04 00:00:00 |
+-------+---------------+-----------------+---------------------+
1 row in set (0.00 sec)
“MySQL” 카테고리의 추천 글
- MySQL IN subquery 성능. IN sub query는 가급적 사용을 피하자
- MySQL의 IN() v.s. EXISTS v.s. INNER JOIN 성능 비교
- MySQL INNER JOIN v.s EXISTS 성능 비교
- JOIN에서 중복된 레코드 제거하기
- MySQL 중복 레코드 관리 방법 - INSERT IGNORE, REPLACE INTO, ON DUPLICATE UPDATE
- MySQL GROUP BY 성능 최적화를 위한 INDEX 설계
- MySQL Query Cache를 빠르게 비우기
- MySQL Plugin에 대한 간단한 소개
- MySQL InnoDB Index Statistics
- MySQL Foreign key 사용 시 주의 사항 (Can’t create table (errno: 150))