2014-03-29 3 views
3

나는이 테이블이 독특한 조합으로 모든 레코드를 찾기 messages두 개의 열

sender_id recipient_id 
1   2 
1   3 
1   3 
2   1 

내가 레코드를 선택하고자하는 등 그 :

  1. 어느 SENDER_ID 또는 receiver_id = current_user.id
  2. 다른 필드는 고유해야합니다.

즉 다음 레코드 만 있습니다. 위의 표에서 선택할 수 있습니다.

sender_id recipient_id 
1   2 
1   3 

왜? 보내고받은 메시지를 집계하는 페이 스북과 같은받은 편지함을 만들고 싶기 때문에이 쿼리는 병목 현상입니다. (A) 내로

SELECT DISTINCT sender_id, reciepient_id 
FROM messages 
WHERE (sender_id = current_user.id or reciepient_id = current_user.id) 

답변

4
SELECT DISTINCT sender_id, recipient_id 
FROM messages 
WHERE $current_user_id IN (sender_id, receiver_id) 
AND sender_id <= receiver_id; 

마지막 조건 접을 필요가 (2,1) 및 (1,2) :

I 레일 3.2 및 POSTGRES ANSI의 SQL로 9.3

+0

와우 ... 그냥 와우 –

+0

완료. http://sqlfiddle.com/#!15/5a39c/5/0 –

+0

@Erwin 가장 최근의 결과를 얻으려면 어떻게 결과를 주문해야합니까? 테이블에는 id 컬럼과 created_at 컬럼이 있는데, 둘 다 정렬에 사용할 수 있습니다. 그러나 어떻게? –

2

사용하고 단일 행.

경우, 예를 달리 (1,2)이도하지 않고 데이터에 (2,1)이있을 수 있습니다, 그것은 더 복잡해진다. UNION 쿼리는 완벽해야

WITH cte AS (
    SELECT sender_id, recipient_id 
    FROM messages 
    WHERE $current_user_id IN (sender_id, receiver_id) 
    ) 
SELECT sender_id, recipient_id FROM cte 
WHERE sender_id <= receiver_id 
UNION 
SELECT recipient_id, sender_id FROM cte 
WHERE sender_id > receiver_id; 

CTE 대신 두 가지의 스캔 단일 인덱스로 아래로 유지하여 빠르게해야한다.

UNION은 결과에서 중복을 제거하여 DISTINCT 단계가 불필요합니다.
정렬 된 출력의 끝에 ORDER BY 절을 끝에 추가 할 수 있습니다.

최상의 성능을 얻으려면 두 열에 모두 인덱스가 필요합니다. 개별 인덱스가 좋은 성능을 가진 bitmax 인덱스 스캔과 결합 될 수 있지만, (sender_id, receiver_id)multicolumn index는 여전히 빨라집니다 :

CREATE INDEX foo_idx ON messages (sender_id, recipient_id); 

는 언제나처럼, 인덱스에 대한 비용과 혜택을 무게. 쿼리에 병목 현상이있는 경우 인덱스가 좋습니다.

+0

만약 당신이'sender_id'와'receiver_id' 둘 다에 독립적 인 인덱스를 가지고 있다면 (PostgreSQL은 비트 맵 인덱스 스캔을 사용하여 일치하는 행을 찾아야합니다. –

+1

중복을 제거하지 못했습니다. –

+0

예 (1,2) 대 (2,1) 중복을 제거하지 않습니다 –