Я заполняю образованными догадками, где информация отсутствует ...
Запрос
Отображаемый вами запрос не идеален для вашей заявленной цели:
Я пытаюсь получить все теги, которые принадлежат всем разговорам пользователя
И под словом «все» вы подразумеваете «любое», которое я предполагаю.
Также предполагается, что ссылкацелостность обеспечивается ограничениями внешнего ключа.Тогда мы можем вырезать посредника conversations
.Присоединение к нему не добавляет ничего, кроме затрат.
При наличии запроса запрос может возвращать одни и те же теги несколько раз.Предполагая, что вам нужны уникальные теги, достаточно утверждать, что любые совпадающие строки в conversation_user_pairs
существуют .Полу-соединение EXISTS
обычно является лучшим способом сделать это:
SELECT t.tag_text_downcased
FROM tags t
WHERE t.user_id = 459 -- assuming it's a numeric data type
AND EXISTS (
SELECT
FROM conversation_user_pairs cu
WHERE cu.user_id = t.user_id
AND cu.conversation_id = t.conversation_id
AND cu.conversation_status = 'active'
);
Индексы
Ваш индекс find_tag_text_downcased_tags
на tags
идеален.
И by_user_and_conversation_and_status
тоже хорошо для этого.Если многие строки не являются «активными», в то время как вас больше всего интересуют активные, частичный индекс может быть даже лучше:
CREATE INDEX ON conversation_user_pairs (user_id, conversation_id)
WHERE conversation_status = 'active';
Другие индексы здесь вам не нужны.И так как у вас есть эти два:
add_index "tags", ["conversation_id", "user_id", "tag_text_downcased"], name: "find_tag_text_downcased_tags"
add_index "tags", ["user_id", "conversation_id"], name: "index_tags_on_user_id_and_conversation_id"
... обычно это тоже не полезно:
add_index "tags", ["conversation_id", "user_id"], name: "index_conversation_first_tags"
Вы, вероятно, можете отбросить его.См .:
В стороне: если conversation_status
имеет только «активный»и «мертвый» или подобный, сделайте это boolean
столбцом.Меньше и дешевле, чем text
.