2015-03-04 2 views
0

Я не база данных профессионально, но в настоящее время работает на одном запросе (PHP-> MySQL):MySQL эффективный ВЫБРАТЬ запрос

У меня есть 3 таблицы:

'Предметы': идентификатор, имя, ссылка

'ItemsToUsers': идентификатор, item_id, user_id

'Пользователи': идентификатор, электронная почта

Каждая доступность 'Item' представляется закономерные изменения, которые я проверить на лету некоторым алгоритмом.

Моя цель состоит в том, чтобы

1) выбрать все элементы и проверить на лету, если они доступны

2) Если товар есть в наличии, уведомить пользователей, которые следят за его по электронной почте. Для этого мне нужно выбрать пользователей из «ItemsToUsers», а затем получить их электронную почту из таблицы «Пользователи».

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

Есть ли способ сделать это более эффективно: в одном запросе или путем изменения алгоритма? Спасибо за ваше время!

+1

Давайте посмотрим макет из SELECT (ов), в котором вы нуждаетесь. Возможно, для подключения трех таблиц вам понадобится только один SELECT с JOINs. –

+0

Используйте ['JOIN'] (http://dev.mysql.com/doc/refman/5.0/en/join.html) и не забудьте индексы в соединенных столбцах. –

+0

Где находится ваша колонка "Доступность"? Я могу видеть только id, имя и ссылку для элемента. – MegaAppBear

ответ

0

Недостаточно информации для определения того, как элемент доступен. Это сильно затрудняет возможность запроса по элементу 2.

Это означает, что мы добавим столбец «доступный» в таблицу Items, которая является tinyint из 0 для недоступности, 1 для доступных.

Запрос, то, что бы получить все адреса электронной почты для лиц, наблюдающих предметы, которые доступны является:

SELECT u.email FROM Users AS u JOIN ItemsToUsers AS k ON k.user_id = u.id JOIN Items AS i on i.id = k.item_id WHERE i.available = 1; 

В качестве альтернативы, вы можете использовать подзапрос и IN.

Предположим, что у вас есть другая таблица с названием Доступность с идентификаторами столбцов, item_id и доступными, что снова является tinyint, содержащим 1 для доступных и 0 для недоступных.

SELECT u.email FROM Users AS u JOIN ItemsToUsers AS k ON k.user_id = u.id WHERE k.item_id IN (SELECT a.item_id FROM Availability AS a WHERE a.available = 1); 

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

+0

Я не сохраняю статус доступности в любом месте - я просто проверяю его на лету во время foreach ($ result as $ row) {}. Но я мог бы сначала проверить их, затем сохранить те, которые доступны, а затем получать электронные письма. Благодарим вас за примеры запросов. – user3078775

+0

Это ваше узкое место. Я бы предложил изменить алгоритм, чтобы напрямую запрашивать доступные продукты. Однако, если это нелегко сделать, вы можете создать хранимую процедуру, которая принимает массив идентификаторов и возвращает все записи с этими идентификаторами. См. Ответ devart на http://stackoverflow.com/questions/8149545/pass-array-to-mysql-stored-routine –

+0

Не входите в привычку 'IN (SELECT ...)' - Производительность действительно Плохо. –

0

Ваши шаги намекают делать это в n+1 queries (где п = число записей в таблице элементов):

SELECT * FROM Items; -- This is the +1 part 

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

SELECT email FROM Users u 
    INNER JOIN ItemsToUsers iu ON iu.user_id = u.id 
    INNER JOIN Items i ON iu.item_id = i.id 
WHERE i.id = {your item id} 

Вы бы выполнения этого запроса для каждого элемента в таблице. Это номер n.

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

SELECT DISTINCT email FROM Users u 
    INNER JOIN ItemsToUsers iu ON iu.user_id = u.id 
    INNER JOIN Items i ON iu.item_id = i.id 
WHERE i.is_active = 1 

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

+0

Да, вы поняли мою озабоченность запуском слишком большого количества запросов - мне очень нравится ваше решение – user3078775

+0

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

+0

Звучит подозрительно, как мой ответ. –

0
SELECT Items.id, Items.name, Items.link FROM Items 
INNER JOIN ItemsToUsers ON ItemsToUsers.item_id = Items.items.id 
INNER JOIN Users ON ItemsToUsers.user_id = Users.id ; 
Смежные вопросы