Pull to refresh

Comments 26

Все логично. В Oracle тоже запрос с использованием динамических названий таблиц или других объектов сначала надо собрать в виде текста, а потом исполнить его в процедуре EXECUTE_IMMEDIATE.
Да я согласен, ничего хитрого тут нет, но такие вопросы возникают с завидной регулярностью, по-этому решил описать.
Создание динамических запросов оправдано только если они выполняются редко или вообще один раз. Иначе это неоправданная нагрузка на парсер. К тому же динамические запросы являются потенциальной дыркой для SQL injection.
Ну если инъекция добралась до автособираемого sql-я, то это дыра в разработчике.
Для MS SQL, например, это не так. Его оптимизатор позволяет сохранять планы даже для динамического SQL. План, грубо говоря — это распарсенное до атомарных операций выражение SQL, готовое к выполнению. После первого парсинга план помещается в кэш, после чего для его использования не нужно нагружать парсер, достаточно просто взять из кеша нужный запрос и подставить параметры.

Понятно, что параметризовать именем таблицы нельзя, зато можно держать планы для всех таблиц в БД (их редко бывает больше сотни-другой) для среднего проекта.

С другой стороны, наличие динамического sql, как правило, говорит о том, что что-то не так в датском королевстве вы используете БД не по назначению, заставляя ее выполнять задачи сервера приложений.
Вон оно как.

А я тупой думал, что когда из клиента запрос на сервер шлю — сервер его сначала парсит и только потом выполняет. И вообще сдуру думал, что любой запрос, если он не в хранимой процедуре, для сервера динамический и его парсить надо.

Спасибо за просветление.

Так все таки, вообще нельзя с клиента запросы слать или они пока до сервера доходят волшебным образом парсятся?
UFO just landed and posted this here
вы еще скажите сэндмэйл )
Это насчет archive_prefix
Согласен, незаметил.
а то даже может и суффикс =)
> DECLARE template,archive_template VARCHAR(50);

тут надо archive_prefix вместо archive_template, опечатка вроде :)
и еще,
SET @archive_query:=CONCAT
(«CREATE TABLE »,template," ENGINE=ARCHIVE AS
(SELECT * FROM ",current_table," )");

Тут обязательно после CONCAT-а нужно поставить открывающую скобу на этой же строке, иначе mysql будет ругаться, что мол нет такой процедуры CONCAT
Спасибо, поправил.
Народ, если не сложно, помогите плз разобраться как правильно сделать выборку, в инете своего случа не нашёл:

Рабочий пример:
SELECT column_name(s)
FROM table_name1
LEFT JOIN table_name2
ON table_name1.column_name = table_name2.column_name
WHERE table_name1.column_description LIKE table_name2.column_description2

Нада в LIKE добавить частичное включение, т.е. LIKE %table_name2.column_description2%
Если у нас таблички t1, t2 для наглядности их JOIN без условия
select name1,d1,name2,d2 from t1 left join t2 on t1.name1=t2.name2

+---------+------+---------+----------+
| name1   | d1   | name2   | d2       |
+---------+------+---------+----------+
| name1   | d1   | name1   | x_d2_x   |
| name11  | d11  | name11  | x_d11_x  |
| name111 | d111 | name111 | x_d111_x |
+---------+------+---------+----------+

То запрос будет выглядить так
select name1,d1,name2,d2 from t1 left join t2 on t1.name1=t2.name2 where LOCATE(d1,d2)

Логика тут такая LOCATE() возвращает позицию вхождения подстроки. Если внутри d2 содержится d1, то мы получим положительное число.
Получим соотвественно:
+---------+------+---------+----------+
| name11  | d11  | name11  | x_d11_x  |
| name111 | d111 | name111 | x_d111_x |
+---------+------+---------+----------+

То есть запись где было d2=x_d2_x была отброшена.
спасибо, наглядно и доходчиво)
Вот если бы результат исполнения хранимых процедур можно было бы использовать в том же запросе, которых их вызывает, в виде таблицы, например, то это было бы дело.

А так приходится использовать для сложной логики выборок хранимые функции, которые замедляют исполнение запросов примерно в 10 раз.
Можно дергать процедуру и выгружать данные в темповую таблицу, конечно не очень красиво, но вполне рабочий вариант.
А какие проблемы.
Если в результате выполнения запроса получается выборка с одним полем — GROPUP_CONCAT на него INTO myvar.
Дальше собрать запрос CONCAT'ом и выполнить.
Если одно значение просто его в переменную.
Если набор строк с несколькими полями, то IMHO лучше на клиента вернуть и там обработать, а по результатам новый запрос отправить. Тут нередко и кэш может помочь.

С темповой таблицей поаккуратнее, она ведь может и на диске образоваться, естественно в самый подходящий момент, в неподходящий, когда нагрузки нет — ей в оперативке места хватит. :)
UFO just landed and posted this here
Ну их нафиг такие извраты, я лучше в php напишу что нибудь вроде: query(«SELECT FROM ?t WHERE ....», $table) :) Всяко удобнее))
Действительно удобней. Но здесь задача стояла как такое сделать средствами MySQL
Так удобно, но все же надо стараться избавляться от динамических запросов. Их минус в том, что компилируются они при каждом вызове, тогда как обычные компилируются только при создании хранимой процедуры.
Ну почему же, они компилируются при PREPARE. Можно один раз PREPARE и кучу раз EXECUTE.

Сам по себе это — инструмент, который можно использовать. И хорошо, что он есть. А уж как его использовать — решать разработчику.
UFO just landed and posted this here
Sign up to leave a comment.

Articles