Один запрос с множеством объединений в одном запросе API или несколько запросов с несколькими объединениями в отдельных запросах API? - PullRequest
4 голосов
/ 20 февраля 2012

Что такое лучшая практика, что обеспечивает лучшую производительность?

В настоящее время у меня есть запрос со многими LEFT JOIN с, который выбирает user и все его данные, такие как друзья, запросы друзей и т. Д.on:

SELECT
    `user`.`id` AS `user_id`,
    `user`.`name` AS `user_name`,
    `manager`.`id` AS `manager_id`,
    `competition`.`id` AS `manager_competition_id`,
    `competition`.`name` AS `manager_competition_name`,
    `competition`.`week` AS `manager_competition_week`,
    `country`.`id` AS `manager_competition_country_id`,
    `country`.`name` AS `manager_competition_country_name`,
    `club_template`.`id` AS `manager_club_template_id`,
    `club_template`.`name` AS `manager_club_template_name`,
    `club`.`id` AS `manager_club_id`,
    `club`.`name` AS `manager_club_name`,
    `club`.`ready` AS `manager_club_ready`,
    `friend`.`friend_id` AS `friend_id`,
    `friend_user`.`name` AS `friend_name`
FROM
    `users` AS `user`
LEFT JOIN
    `managers` AS `manager`
ON
    `manager`.`user_id` = `user`.`id`
LEFT JOIN
    `competitions` AS `competition`
ON
    `competition`.`id` = `manager`.`competition_id`
LEFT JOIN
    `countries` AS `country`
ON
    `country`.`id` = `competition`.`country_id`
LEFT JOIN
    `club_templates` AS `club_template`
ON
    `club_template`.`id` = `manager`.`club_template_id`
LEFT JOIN
    `clubs` AS `club`
ON
    `club`.`id` = `manager`.`club_id`
LEFT JOIN
    `friends` AS `friend`
ON
    `friend`.`user_id` = `user`.`id`
LEFT JOIN
    `users` AS `friend_user`
ON
    `friend_user`.`id` = `friend`.`friend_id`
WHERE
    `user`.`id` = 1

Как видите, это очень большой запрос.Я обосновал это тем, что лучше иметь только один запрос, который можно выполнить в одном запросе API, например, ...

/api/users/1

... против нескольких запросов, каждый в своем собственном запросе API.вот так ...

/api/users/1
/api/users/1/friends
/api/users/1/friend_requests
/api/users/1/managers

Но теперь я обеспокоен тем, что, поскольку он стал таким огромным запросом, он фактически повредит производительности, а не разделит его на отдельные запросы API.

Что будет лучше масштабироваться?

Обновление

Я изменил запрос на полный запрос.Это не последний запрос;Я планирую добавить еще больше объединений (или нет, зависит от ответа).

Каждая таблица имеет PRIMARY KEY на id.Все столбцы ассоциации (competition_id, club_id и т. Д.) Имеют регулярные INDEX.Ядром базы данных является InnoDB.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2012

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

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

Вы можете предоставитьхотя оба.Из соглашения об именах проясните, что дорогая версия возвращает все данные и предназначена для использования, когда в противном случае пользователю может понадобиться совершить, скажем, 20 - 30 вызовов, чтобы получить полную картину.

Примеры:

1 - представьте, что вам нужно получить этот полный пользовательский объект, чтобы узнать имя.Действительно расточительно.И если это произойдет непреднамеренно в большом цикле, может произойти ловушка производительности.Предпочитайте метод getUserName(id), который просто считывает это одно значение назад.

2 - с другой стороны, если вы хотите отобразить полный профиль пользователя на странице, тогда наиболее эффективный getFullUserProfile(id) наиболее эффективен (1 звонок, а не 10 - 20).

Редактировать - еще один полезный пример.Предвидя, где запрашивается много значений , например, вместо того, чтобы принудительно вызывать вызывающую программу getUserName(id) 500 раз, чтобы получить все имена для определенного условия (возможно, всех администраторов?), Укажите List<String> getAdminUserNames(), который предоставляет всеэти данные в один вызов.

1 голос
/ 20 февраля 2012

Классный вопрос.

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

Итак, сделав дикую догадку на основе вашего запроса, у вас есть пользователи в разных состояниях завершения - пользователи, которые создали свой профиль, но еще не присоединились к конкурсу; пользователи, которые присоединились к конкурсу, но еще не образовали клуб и т. д. Это отражает модель вашего домена. Я ожидаю, что ваш API отразит это - поэтому, используя ваш спокойный пример:

/api/users/profile
/api/users/signedUpUsers/
/api/users/usersWithClubs/

Первый вызов (/ api / users / profile) позволяет вам вернуть профиль пользователя, но никакие детали вашего внешнего соединения, кроме состояния пользователя (и, возможно, URL-адреса, где можно найти другие дополнительные данные).

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

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