2012-02-20 3 views
4

Что такое лучшая практика, что обеспечивает лучшую производительность?Один запрос со многими объединениями в одном запросе API или несколько запросов с некоторыми объединениями в отдельных запросах API?

я в настоящее время есть запрос со многими LEFT JOIN с, что извлекает user и все его данные, как друзья, друг запросы, и так далее:

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.

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

Update

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

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

+1

Было бы полезно, если бы вы могли предоставить некоторую информацию по структуре и ключам базы данных, а также полный запрос –

+0

Выполнено. Дайте мне знать, если вам нужно больше – Rits

ответ

2

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

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

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

Примеры:

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

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

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

1

Прохладный вопрос.

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

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

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

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

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

Смежные вопросы