2015-02-15 2 views
1

Я пытаюсь получить список друзей из моей базы данных, и мой запрос работает, но занимает много времени, чтобы загрузить результаты (иногда около 10 секунд).Как ускорить мой запрос «Список друзей» MySQL?

Здесь:

SELECT F.status, U.username, U.email, UI.country, UI.birthday, P.thumb_url 
FROM user U, relation F, user_info UI, photo P 
WHERE 
CASE 
WHEN F.leader = 'USER_ID' 
THEN F.subscriber = U.id 
WHEN F.subscriber= 'USER_ID' 
THEN F.leader= U.id 
END 
AND 
U.id = UI.user_id 
AND 
UI.main_photo = P.id 
AND 
F.status='1'; 

Мой «отношение» таблица выглядит следующим образом:

CREATE TABLE IF NOT EXISTS `relation` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `leader` int(11) NOT NULL, 
    `subscriber` int(11) NOT NULL, 
    `time` timestamp NOT NULL DEFAULT, 
    `status` int(11) NOT NULL DEFAULT '0', 
    `seen` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `id` (`id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; 

Так что мой вопрос: есть ли у вас какие-то хорошие предложения, чтобы улучшить мой запрос?

Спасибо!

+1

Вы, кажется, использует фильтры, где вы должны использовать таблицу соединений. – Hamish

+0

Ключевое слово join существует около 25 лет. Лучше всего использовать его. – Bohemian

+0

Я собираюсь предположить, что 'USER_ID' является заполнителем идентификатора пользователя, для которого вы строите список. Также ваша схема недействительна, время не имеет ПО УМОЛЧАНИЮ. – Schwern

ответ

0

Спасибо за ваши ответы.

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

SELECT username, email, ui.gender, ui.country, ui.birthday, p.thumb_url 
FROM relation 
RIGHT JOIN user ON 
(user.`id` = relation.`leader` 
OR 
user.`id` = relation.`subscriber`) 
AND 
user.`id` != '?' 
AND 
relation.`status` = '1' 
JOIN user_info ui, photo p 
WHERE 
(relation.`leader` = '?' 
OR 
relation.`subscriber` = '?') 
AND user.`id` = ui.`user_id` 
AND ui.`main_photo` = p.`id`; 

Этот запрос занимает только около 100 мс, чтобы загрузить результаты, тогда это было около 5 секунд для первого я отправил ...

+0

Да, соединение по отношению имеет смысл для создания списка друзей. Есть еще способы улучшить этот запрос, я добавлю его к моему ответу. – Schwern

+0

PS Почему вы определились с ПРАВОЙ ПРИСОЕДИНЕНИЕ? – Schwern

3

Как правило, если вы используете CASE (или любую другую if/then logic) в SQL, вы, вероятно, ошибаетесь. SQL - это декларативный язык, что означает, что вы задаете ему вопросы. Если вы говорите, как ответить на вопрос, это, вероятно, закончится плохо (или медленно). Ключ состоит в том, чтобы поместить сдерживающий ID пользователя в предложение WHERE и оставить его вне соединения. Это заставляет его не сообщать базе данных о том, как выполнять свою работу, задавать базу данных. База данных позаботится обо всем остальном.

Использование синтаксиса JOIN позволяет уточнить, что такое соединение и какое ограничение. SQL joins - это то, что нужно использовать, когда вам нужны строки из нескольких таблиц, сшитых вместе. Базы данных знают, как их оптимизировать.

Второй бит - use EXPLAIN, чтобы рассказать вам, как MySQL выполняет запрос, где он медленный. Обычно это указывает, где вам нужны индексы или какая часть запроса должна быть переписана.

я буду считать, что Relationship.leader и Relationship.subscriber являются внешними ключами на User.id и описать, кто следует, что пользователь, и кто они следуют, и вы хотите, чтобы показать, что каждый пользователь, связанный с данным USER_ID. В CASE не должно быть необходимости, вы можете просто проверить, совпадают ли они (проверьте меня на этом).

SELECT F.status, U.username, U.email, UI.country, UI.birthday, P.thumb_url 
FROM user U 
JOIN user_info UI 
    ON U.id = UI.user_id 
JOIN photo P 
    ON UI.main_photo = P.id 
JOIN relation F 
    ON F.leader = U.id OR F.subscriber = U.id 
WHERE F.status='1' 
    AND U.id = ? 

UPDATE: Понимание теперь, что он должен быть список друзей пользователя, изменить U.id = ? проверить, что пользователь находится в отношениях, а не.

Мы хотим найти список отношений, но мы используем пользователей в качестве основной таблицы. Это немного неудобно. @fraxool's query which is FROM relation имеет больше смысла, но он может использовать некоторую очистку о том, что такое ограничение. JOIN ON - только о сетчатых столах. ГДЕ для ограничения того, что возвращается в целом. Применение этих принципов к новому запросу @ fraxool, мы получаем ...

SELECT username, email, ui.gender, ui.country, ui.birthday, p.thumb_url 
FROM relation R 
JOIN user U 
    ON U.id = R.leader OR U.id = R.subscriber 
JOIN user_info UI 
    ON U.id = UI.user_id 
JOIN photo P 
    ON UI.main_photo = P.id 
WHERE R.status = 1 
    AND (R.leader = ? OR R.subscriber = ?) 

Дополнительное ограничение U.id != ? ненужно, если вы не можете быть ваш собственный друг. Это то, что должно быть обработано в ограничениях столбцов для отношений .leader и relation.subscriber.

+0

Спасибо за ваш замечательный ответ! На самом деле, я также пробовал с синтаксисом JOIN, но это дало мне неправильные результаты ... Но я думаю, что мой запрос был неправильным. С вашим запросом у меня есть список результатов с правильным количеством строк ... Но он возвращает информацию о текущем пользователе (где U.id =?) В каждой строке, и я хочу, чтобы информация друзей этого пользователя. Я на самом деле работаю над вашим запросом, но если у вас есть предложение, я возьму его тоже! Еще раз спасибо! – fraxool

+0

@fraxool Я думаю, что меняю 'U.id =?' На 'F.leader =? OR F.subscriber =? 'Сделает это. – Schwern

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