вопрос MySQL-ниндзям

программирование php MySQL базы данных

Подскажите, уважаемые. Как лучше реализовать такую штукенцию.

Есть таблица, из которой сложным запросом вытягиваются id-шники строк, находящихся в другой таблице. Затем этот набор id-шников будет использован для получения строк из нескольких других таблиц с объединением по UNION, короче суть в том, что набор id-шников будет использован несколько раз.

Как сделать так, чтобы первый запрос не повторять много раз ?

Вот структурно схема процесса, чтобы было понятнее:
второй запрос имеет вид

(select
t0.eti_id, 0 as k, t0.dat as dat0, NULL dat1, NULL dat2, NULL dat3
from `ed_0` t0
where t0.e_id = 248)
union
(select
t1.eti_id, 1 as k, NULL dat0, t1.dat as dat1, NULL dat2, NULL dat3
from `ed_1` t1
where t1.e_id = 248)
union
(select
t2.eti_id, 2 as k, NULL dat0, NULL dat1, t2.dat as dat2, NULL dat3
from `ed_2` t2
where t2.e_id = 248)
union
(select t3.eti_id, 3 as k, NULL dat0, NULL dat1, NULL dat2, t3.dat as dat3
from `ed_3` t3
where t3.e_id = 248)

Вот такой примерно запрос. Но фишка в том, что вместо e_id = 248 я бы хотел тут видеть выборку по in () из какого-то массива. Писать один и тот же запрос внутри in () - не резон, т.к. он здоровенный, хотя и может вернуть всего несколько значений (но может и пару тысяч, поэтому конструировать массив ID в PHP - тоже не резон).

Как быть ?

Примечание:
2 Максим ХМ
Я тоже думал про хранимую процедуру, но как-то не созрел. Можешь привести структурный пример как это может выглядеть ?

Примечание:
2 crimaniak
Ну почему же не воспользовался. Очень даже воспользовался. Сейчас у меня сделано практически как у тебя, есть таблица для int'ов, таблица для string, таблица для float и datetime. Пока 4х типов хватает. В каждой таблице в строке хранится e_id, eti_id и dat. e_id - это индентификатор сущности (объекта), eti_id - это идентификатор идентификатора поля (т.е. если в разных типах сущностей встречается поле, например, first_name, то соответствующий ему eti_id у всех объектов будет одинаковым.
А UNION взялся оттого, что я не выбираю каждое свойство в свой столбец, а выбираю кучкой и потом в PHP построчно в цикле разбираю и раскладываю в объект (или в массив).
Наверное, можно выбрать и столбиками... надо подумать. Только я думаю, что такой запрос будет гораздо дольше выполняться.

Примечание:
Выборка через UNION удобна для получения свойств одной сущности (объекта), поскольку они все разного размера и распихивать лучше всего на стороне PHP.

Примечание:
Хотя вариант с получением прямоугольного ответа мне сейчас уже тоже нравится и надо будет его протестить, вдруг с учётом всех накладных расходов он получится шустрее.

Смущает только, что в лимитах MySQL вроде бы нельзя больше 61 штуки join'ов в одном запросе делать. А у меня может быть и более 61 поля в сущности (пока нет, но в перспективе).

Примечание:
Удивительная-таки вещь!
Я сделал выборку одной строкой, получился гигантский запрос из 36 джойнов, но как ни странно, работает он в сотни раз быстрее!!!!

Я не знаю чем это объясняется, вряд ли кэшированием, поскольку такое же время (ну может в 2 раза больше) требуется запросу на выполнение сразу после перезагрузки MySQL-сервера. А после рефреша и того меньше. В общем, оно в 1,5 раза больше, чем выборка моим вышеописанным способом с UNION'ами. Похоже, что UNION - чертовски медленная операция или я чего-то не понимаю в этой жизни.

В общем спасибо, пошёл переписывать класс (в чётвертый раз).

Насчёт классов - у меня тут как таковых классов и нет, свойства генерируются на лету динамически (__get/__set), поэтому с этим не возникает проблем. Весь класс весит всего 650 строк вместе со всеми свистелками и перделками.
Ответы:
Может, загнать это дело в хранимую процедуру и внутри уже курсор использовать несколько раз? Правда тут тоже придётся попариться, как потом из нескольких таблиц это собрать.
К дополнению.
Да вот тоже в голову ничего разумного не приходит. Нужно уточнить, можно ли к курсору добавлять ряды, тогда я бы сделал так:
1) Курсор для выборки e_id
2) Пустой курсор для вывода
3) 4 прохода по добавлению во второй курсор новых рядов (то бишь запросы из юнионов)
4) Возвращаем второй курсор.
Единственное что — я не уверен, что можно таким образом собирать результат и что функция может возвращать курсор (в pgsql точно может, я этим даже пользовался).
Вопрос в том, насколько тормозной этот вложенный запрос. Если он достаточно быстр и тебе просто не хочется пихать везде его из-за длины, то проще всего сделать VIEW на основе этого запроса и потом использовать VIEW, причем не с where, а, наверное, лучше с inner join viewName on e_id=viewName.id. В этом случае сервер имеет возможность раскрыть VIEW и оптимизировать общий запрос.
Другие варианты - создавать временную таблицу и селектить список айдишников туда, а потом использовать её по inner join, или вообще сохранять его снаружи сервера и потом вставлять в запросы как строку ... e_id in ($idList) ...
Можно попробовать извращение - сделать запрос с union нефильтрованным и потом использовать его как вложенный во внешнем запросе, в котором уже отфильтровать по e_id.
Связываться с хранимыми процедурами только ради решения этой задачи крайне не рекомендую. Овчинка выделки не стоит.


13 лет назад

RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.

Все вопросы, добавленные на сайт ответов Google, мы скопировали и сохранили здесь. Имена старых пользователей также отображены в том виде, в котором они существовали ранее. Только нужно заново пройти регистрацию, чтобы иметь возможность задавать вопросы, или отвечать другим.

Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.