ИЛИ запросить производительность и стратегии с Postgresql - PullRequest
1 голос
/ 23 февраля 2010

В моем приложении есть таблица событий приложения, которые используются для генерации пользовательского потока событий приложения. Поскольку он генерируется с использованием запроса OR, меня беспокоит производительность этого интенсивно используемого запроса, и мне интересно, подхожу ли я к этому неправильно.

В приложении пользователи могут следить как за другими пользователями, так и за группами. Когда действие выполняется (например, создается новое сообщение), создается запись feed_item с actor_id, установленным для идентификатора пользователя, и subject_id, установленным для идентификатора группы, в которой было выполнено действие, и actor_type и subject_type устанавливаются на имена классов моделей. Так как пользователи могут следить как за группами, так и за пользователями, мне нужно сгенерировать запрос, который проверяет и actor_id, и subject_id, и ему нужно выбрать отдельные записи, чтобы избежать дублирования. Так как это запрос ИЛИ, я не могу использовать нормальный индекс. И поскольку запись создается каждый раз при выполнении действия, я ожидаю, что в этой таблице будет много записей довольно быстро.

Вот текущий запрос (таблица following объединяет пользователей с feeders, то есть пользователей и групп)

SELECT DISTINCT feed_items.* FROM "feed_items" 
 INNER JOIN "followings" 
 ON (
 (followings.feeder_id = feed_items.subject_id 
 AND followings.feeder_type = feed_items.subject_type)
 OR
 (followings.feeder_id = feed_items.actor_id 
 AND followings.feeder_type = feed_items.actor_type)
 )
 WHERE (followings.follower_id = 42) ORDER BY feed_items.created_at DESC LIMIT 30 OFFSET 0

Итак, мои вопросы:

  • Поскольку это часто используемый запрос, есть ли здесь проблема с производительностью?

  • Есть ли какой-нибудь очевидный способ упростить или оптимизировать это, что мне не хватает?

Ответы [ 3 ]

1 голос
/ 23 февраля 2010

То, что у вас есть, называется эксклюзивной дугой , и вы понимаете, почему это плохая идея. Наилучший подход для решения этой проблемы - сделать тип элемента фида динамическим:

  • Элементы фида: id, тип (A или S для субъекта или субъекта), подтип (заменяет actor_type и subject_type)

и тогда ваш запрос становится

SELECT DISTINCT fi.*
FROM feed_items fi
JOIN followings f ON f.feeder_id = fi.id AND f.feeder_type = fi.type AND f.feeder_subtype = fi.subtype

или аналогичный.

Это может не полностью или точно отражать то, что вам нужно сделать, но принцип здравый: вам нужно устранить причину условия ИЛИ, изменив вашу модель данных таким образом, чтобы можно было писать производительные запросы против это.

1 голос
/ 23 февраля 2010

Объясните анализ и время запроса, чтобы увидеть, есть ли проблема.

Также вы можете попытаться выразить запрос как объединение

SELECT x.* FROM
(
SELECT feed_items.* FROM feed_items
INNER JOIN followings 
ON  followings.feeder_id = feed_items.subject_id 
    AND followings.feeder_type = feed_items.subject_type
WHERE (followings.follower_id = 42)
UNION
SELECT feed_items.* FROM feed_items
INNER JOIN followings
 followings.feeder_id = feed_items.actor_id 
 AND followings.feeder_type = feed_items.actor_type)
WHERE (followings.follower_id = 42)
) AS x
ORDER BY x.created_at DESC 
LIMIT 30

Но опять объясните, проанализируйте и сравните.

0 голосов
/ 23 февраля 2010

Чтобы выяснить, есть ли проблема с производительностью, измерьте ее. PostgreSQL может объяснить это для вас.

Я не думаю, что запрос нужно упростить, если вы обнаружите проблему с производительностью, возможно, вам придется пересмотреть свои индексы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...