@Alexの答えIN
はcount()
おそらく最も単純な解決策ですが、このPL/pgSQL関数の方が高速であると期待しています。
CREATE OR REPLACE FUNCTION f_conversations_among_users(_user_arr int[])
RETURNS SETOF conversations AS
$BODY$
DECLARE
_sql text := '
SELECT c.*
FROM conversations c';
i int;
BEGIN
FOREACH i IN ARRAY _user_arr LOOP
_sql := _sql || '
JOIN conversations_users x' || i || ' USING (conversation_id)';
END LOOP;
_sql := _sql || '
WHERE TRUE';
FOREACH i IN ARRAY _user_arr LOOP
_sql := _sql || '
AND x' || i || '.user_id = ' || i;
END LOOP;
/* uncomment for conversations with exact list of users and no more
_sql := _sql || '
AND NOT EXISTS (
SELECT 1
FROM conversations_users u
WHERE u.conversation_id = c.conversation_id
AND u.user_id <> ALL (_user_arr)
)
*/
-- RAISE NOTICE '%', _sql;
RETURN QUERY EXECUTE _sql;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;
電話:
SELECT * FROM f_conversations_among_users('{1,2}')
関数は動的にビルドし、次の形式のクエリを実行します。
SELECT c.*
FROM conversations c
JOIN conversations_users x1 USING (conversation_id)
JOIN conversations_users x2 USING (conversation_id)
...
WHERE TRUE
AND x1.user_id = 1
AND x2.user_id = 2
...
このフォームは、リレーショナル除算のクエリの広範なテストで最高のパフォーマンスを発揮しました。
アプリでクエリを作成することもできますが、1つの配列パラメーターを使用することを前提としています。また、これはとにかくおそらく最速です。
どちらのクエリでも、高速であるためには次のようなインデックスが必要です。
CREATE INDEX conversations_users_user_id_idx ON conversations_users (user_id);
複数列のプライマリ(または一意の)キー(user_id, conversation_id)
も同様ですが、1つ(conversation_id, user_id)
(非常によくあるように!)は劣ります。上記のリンクで短い理論的根拠を見つけるか、dba.SEのこの関連する質問の下で包括的な評価を見つけます
また、に主キーがあると仮定しますconversations.conversation_id
。
EXPLAIN ANALYZE
@Alexのクエリとこの関数を使用してパフォーマンステストを実行し、結果を報告できますか?
どちらのソリューションも、追加のユーザーとの会話を含め、少なくともアレイ内のユーザーが参加する会話を見つけることに注意してください。
それらを除外したい場合は、関数の追加句のコメントを外します(または他のクエリに追加します)。
関数の機能についてさらに説明が必要な場合は教えてください。