SELECT WHERE IN: Подскажите оптимальный вариант взаимодействия PHP — MySQL
Здравствуйте.
Как сделать правильней, как сделать оптимальней?
1 вариант:
Получаем результат первого запроса:
SELECT `ID` FROM `TABLE_A`WHERE `FIELD_C` = '123';
Подставляем рез-т первого запроса во второй запрос:
SELECT * FROM `TABLE_B` WHERE `FIELD_A` IN ('результат 1-ого запроса');
Итого транзакций: 2
Возникает вопрос: а если результатом первого запроса будет 1k идентификаторов?
2 вариант:
SELECT * FROM `TABLE_B` WHERE `FIELD_A` IN (SELECT `ID` FROM `TABLE_A`WHERE `FIELD_C` = '123');
Итого транзакций: 1
Возникает вопрос: не является ли этот запрос сложным?
Смысл моего вопрос в следующем: в статьях про архитектуру высоконагруженных систем (например, таких как twitter) рекомендуется при взаимодействии с БД использовать простые запросы, а формирование результата проводить на вычислительных серверах (их проще масштабировать).
Так вот, что лучше:
— 1 вариант с двумя простыми запросами к БД, но, возможно, сложным для разбора вторым запросом, если кол-во передаваемых идентификаторов, например тысяча?
— 2 вариант с одним запросом, но вложенным?
>в статьях про архитектуру высоконагруженных систем (например, таких как twitter)
пока у вас нет нагрузок как у Твиттера, не делайте так. только усложните себе жизнь, написанием своих собственных джойнов на php
inner join != left join. inner join синоним перечисления таблиц через запятую:
select * from tableA join tableB using (someFiled)
и
select * from tableA, tableB
where tableA.someField = tableB.someField
Эти две записи синонимы, так что inner join-ов бояться не следует.
Если таблицы однотипные (это касается и полей, и движков) и не используется (не эффективно) кэширование, то лучше 2 вариант.
В остальных случаях 1 вариант.
Вообще, если уж начали про архитекруту, то просто сделайте так:
tableB->getAll();
Как внутри все будет работать пока что Вас не должно волновать, главное чтоб этот метод (функция) возвращала _всегда_ одни и те же данные. Потом когда (если?) будет тормозить, или Вас будет что-то не устраивать Вы этот метод переделаете как душа пожелает.
Так что не важно что именно вы сделаете, главное выделяйте такие спорные вопросы в одном месте, которое _всегда_ возвращает одни и те же данные, как бы Вы его не меняли.
Если выбрать второй вариант, нельзя будет сделать дешевую оптимизацию разнесением таблиц на разные сервера. То есть в этом случае с ростом нагрузки придется покупать массивы дисков, многопроцессорные ядра и прочую хрень. А потом ломать руки архитектору и переписывать весь код.
А в первом случае банально разносим таблицы по серверам и еще годик бездельничаем.
Также, с первым вариантом, сущности можно дергать частично из кеша мультизапросом. А второй вариант хрен закешируешь.
Так что не слушайте джойнеров, потом жалеть будете.
> Возникает вопрос: а если результатом первого запроса будет 1k идентификаторов?
Ну в этом случае все равно у вас код, который эти записи будет отображать в шаблоне, будет тормозить гораздо сильнее, чем код выборки 1000 записей из БД. Так что не стоит беспокоиться.
При использовании сложных запросов риск появления необъяснимых тормозов возрастает в разы.
> очень хочу узнать про проект в котором это таки понадобилось сделать
А что не так с этим вариантом? Есть такой проект, (даже думаю не один), где сервер БД не выдерживает нагрузки (даже с учетом мемкеша, правильных индексов и прочего, так как там в секунду много хитов и большие размеры таблиц, много пользователей) и таблицы раскиданы по нескольким серверам. Что за проект, называть не хочу.
Если у вас есть какой-то проект, где начинаются проблемы с нагрузкой на БД, вы можете протестировать этот способ, и убедиться, что он работает, при правильном подходе. Если у вас такой задачи нет, смысл что-то обсуждать? Доказывать, что 2 или 3 сервера могут обработать больше запросов, чем 1, я не вижу смысла.
>Доказывать, что 2 или 3 сервера могут обработать больше запросов, чем 1
а жаль. потому что обычно получается наоборот и два три сервера работают заметно медленнее чем один, написание слоя абстракции от того что у вас несколько серверов занимает нереальное время, а администрировать это вообще невозможно.
Я за вариант 2. если нет варианта 3.
Вариант 1 может иногда не работать из-за попадания на лимиты:
можно попасть на 2 лимита
1. превышение максимальной длины запроса
2. превышение максимального количества параметров в IN. да, там тоже есть ограничения
Ограничения есть не только в мускуле, но и в оракле, постргессе и других БД.
Вариант 2 ещё к тому же и тормознутый, если у нас много записей во внешнем запросе.
Простые запросы будут работать быстрее:
select * from table1,table2 where условия
или запрос через
join
select * from table1 join table2 on условие where условия
какие из них, будет работать быстрее смотрите сами. Настройки БД подпиливаются под данные и под запросы, которые будут исполняться на этих данных.
Цель таких оптимизаций — это сделать так, чтобы база делала как можно меньше, а приложение, которое работает с базой, как можно больше. Ведь базу трудно масштабировать, а серверов, на которых крутится приложение, добавить легко.
Если у вас один сервер под приложение и под базу, то такая оптимизация вредна, потому что приложение не сделает быстрее то, что сделает база в большинстве случаев. Поэтому надо использовать inner join.
Если Вы интересуетесь из академических соображений или уже готовы к закупкам новых серверов, то первый вариант лучше.