15.5 Предзаготовленные запросы
MySQL 9.2 поддерживает предзаготовленные запросы на стороне сервера. Эта поддержка использует преимущества эффективного двоичного протокола клиент/сервер. Использование предзаготовленных запросов с плейсхолдерами для значений параметров имеет следующие преимущества:
Меньшая нагрузка на обработку запроса каждый раз при его выполнении. Как правило, приложения баз данных обрабатывают большие объемы почти одинаковых запросов, с изменениями только в значениях литералов или переменных в таких клаузах, как
WHEREдля запросов и удалений,SETдля обновлений иVALUESдля вставок.-
Защита от атак SQL-инъекций. Значения параметров могут содержать неэкранированные символы кавычек и разделителей SQL.
Следующие разделы содержат обзор характеристик предзаготовленных запросов:
Предзаготовленные запросы в приложениях
Вы можете использовать предзаготовленные запросы на стороне сервера через интерфейсы программирования клиентов, включая для C-программ, для Java-программ и для программ, использующих технологии .NET. Например, C API предоставляет набор функций, составляющих API предзаготовленных запросов. См. . Другие языковые интерфейсы могут предоставлять поддержку предзаготовленных запросов, использующих двоичный протокол, путем связывания с C-клиентской библиотекой, одним примером является mysqli расширение, доступное в PHP 5.0 и более поздних версиях.
Предзаготовленные запросы в скриптах SQL
Доступен альтернативный SQL-интерфейс для предзаготовленных запросов. Этот интерфейс не так эффективен, как использование двоичного протокола через API предзаготовленных запросов, но не требует программирования, поскольку он доступен непосредственно на уровне SQL:
Вы можете использовать его, когда у вас нет доступного интерфейса программирования.
Вы можете использовать его из любой программы, которая может отправлять SQL-запросы на сервер для выполнения, например, программы-клиента mysql.
Вы можете использовать его даже если клиент использует старую версию клиентской библиотеки.
Синтаксис SQL для предзаготовленных запросов предназначен для использования в таких ситуациях:
Для тестирования работы предзаготовленных запросов в вашем приложении перед его кодированием.
Для использования предзаготовленных запросов, когда у вас нет доступа к API программирования, которое их поддерживает.
Для интерактивного устранения неполадок с предзаготовленными запросами в приложении.
Для создания тестового случая, который воспроизводит проблему с предзаготовленными запросами, чтобы вы могли отправить отчет об ошибке.
Запросы PREPARE, EXECUTE и DEALLOCATE PREPARE
Синтаксис SQL для предзаготовленных запросов основан на трех SQL-запросах:
PREPAREготовит запрос к выполнению (см. Раздел 15.5.1, «Запрос PREPARE»).EXECUTEвыполняет предзаготовленный запрос (см. Раздел 15.5.2, «Запрос EXECUTE»).DEALLOCATE PREPAREосвобождает предзаготовленный запрос (см. Раздел 15.5.3, «Запрос DEALLOCATE PREPARE»).
Следующие примеры демонстрируют два эквивалентных способа подготовки запроса, вычисляющего гипотенузу треугольника, заданного длинами двух сторон.
Первый пример показывает, как создать предзаготовленный запрос, используя строковый литерал для указания текста запроса:
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 5 |
+------------+
mysql> DEALLOCATE PREPARE stmt1;
Второй пример аналогичен, но предоставляет текст запроса как переменную пользователя:
mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 10 |
+------------+
mysql> DEALLOCATE PREPARE stmt2;
Вот дополнительный пример, который демонстрирует, как выбрать таблицу, над которой необходимо выполнить запрос во время выполнения, сохраняя имя таблицы как переменную пользователя:
mysql> USE test;
mysql> CREATE TABLE t1 (a INT NOT NULL);
mysql> INSERT INTO t1 VALUES (4), (8), (11), (32), (80);
mysql> SET @table = 't1';
mysql> SET @s = CONCAT('SELECT * FROM ', @table);
mysql> PREPARE stmt3 FROM @s;
mysql> EXECUTE stmt3;
+----+
| a |
+----+
| 4 |
| 8 |
| 11 |
| 32 |
| 80 |
+----+
mysql> DEALLOCATE PREPARE stmt3;
Предзаготовленный запрос специфичен для сеанса, в котором он был создан. Если вы завершите сеанс, не деактивировав ранее подготовленный запрос, сервер автоматически его деактивирует.
Предзаготовленный запрос также глобален для сеанса. Если вы создаете предзаготовленный запрос внутри хранимой процедуры, он не деактивируется при завершении хранимой процедуры.
Чтобы защититься от одновременного создания слишком большого количества предзаготовленных запросов, установите системную переменную max_prepared_stmt_count. Чтобы запретить использование предзаготовленных запросов, установите значение 0.
Разрешенный синтаксис SQL в предзаготовленных запросах
Следующие SQL-запросы могут быть использованы как предзаготовленные запросы:
ALTER {INSTANCE | TABLE | USER}
ANALYZE
CALL
CHANGE {REPLICATION SOURCE TO | REPLICATION FILTER}
CHECKSUM
COMMIT
{CREATE | DROP} INDEX
{CREATE | DROP | RENAME} DATABASE
{CREATE | DROP | RENAME} TABLE
{CREATE | DROP | RENAME} USER
DEALLOCATE PREPARE
DROP VIEW
DELETE
DO
EXECUTE
FLUSH
GRANT {ROLE}
INSERT
INSTALL PLUGIN
KILL
OPTIMIZE
PREPARE
REPAIR TABLE
REPLACE
REPLICA {START | STOP}
RESET
REVOKE {ALL | ROLE}
SELECT
SET ROLE
SHOW {BINLOG EVENTS | BINARY LOGS | BINARY LOG STATUS | CHARACTER SETS | COLLATIONS | DATABASES | ENGINES |
ERRORS | EVENTS | FIELDS | FUNCTION CODE | FUNCTION STATUS | GRANTS | KEYS | OPEN TABLES |
PLUGINS | PRIVILEGES | PROCEDURE CODE | PROCEDURE STATUS | PROCESSLIST | PROFILE | PROFILES |
RELAYLOG EVENTS | REPLICAS | REPLICA STATUS | STATUS | PROCEDURE STATUS | TABLE STATUS | TABLES |
TRIGGERS | VARIABLES | WARNINGS}
SHOW CREATE { DATABASE | EVENT | FUNCTION | PROCEDURE | TABLE | TRIGGER | USER | VIEW}
TRUNCATE
UNINSTALL PLUGIN
UPDATE
CREATE TABLE ... START TRANSACTION не поддерживается в предзаготовленных запросах.
Другие запросы не поддерживаются.
Для соответствия стандарту SQL, который гласит, что диагностические запросы не могут быть подготовлены, MySQL не поддерживает следующие запросы в качестве предзаготовленных:
SHOW COUNT(*) WARNINGSSHOW COUNT(*) ERRORSЗапросы, содержащие ссылки на системную переменную
warning_countилиerror_count.
В целом, запросы, не разрешенные в предзаготовленных SQL-запросах, также не разрешены в хранимых программах. Исключением являются случаи, указанные в Разделе 27.9, «Ограничения хранимых программ».
Изменения метаданных таблиц или представлений, на которые ссылаются предзаготовленные запросы, обнаруживаются и приводят к автоматической переподготовке запроса при его следующем выполнении. Для получения дополнительной информации см. Раздел 10.10.3, «Кэширование предзаготовленных запросов и хранимых программ».
Плейсхолдеры могут использоваться для аргументов клаузы LIMIT при использовании предзаготовленных запросов. См. Раздел 15.2.13, «Запрос SELECT».
Плейсхолдеры не поддерживаются в предзаготовленных запросах, содержащих DDL событий. Попытка использовать плейсхолдер в таком запросе отклоняется запросом PREPARE с ошибкой Ошибка 6413 (HY000): Динамические параметры могут использоваться только в DML-запросах. Вместо этого вы можете сделать это повторно используемым способом, собрав текст, содержащий SQL события в теле хранимой процедуры, передавая любые переменные части SQL-запроса в качестве параметров IN хранимой процедуре; затем вы можете подготовить собранный текст с помощью запроса PREPARE (также в теле хранимой процедуры), затем вызвать процедуру с желаемыми значениями параметров. См. Раздел 15.1.13, «Запрос CREATE EVENT», для примера.
В предзаготовленных запросах CALL, используемых с PREPARE и EXECUTE, поддержка плейсхолдеров для параметров OUT и INOUT доступна начиная с MySQL 9.2. См. Раздел 15.2.1, «Запрос CALL», для примера и обходного решения для более ранних версий. Плейсхолдеры могут использоваться для параметров IN независимо от версии.
Синтаксис SQL для предзаготовленных запросов не может использоваться вложенным способом. То есть, запрос, переданный в PREPARE, не может сам быть запросом PREPARE, EXECUTE или DEALLOCATE PREPARE.
Синтаксис SQL для предзаготовленных запросов отличается от использования вызовов API предзаготовленных запросов. Например, вы не можете использовать функцию C API для подготовки запроса PREPARE, EXECUTE или DEALLOCATE PREPARE.
Синтаксис SQL для подготовленных запросов может использоваться в хранимых процедурах, но не в хранимых функциях или триггерах. Однако курсор не может использоваться для динамического запроса, который подготовлен и выполнен с помощью PREPARE и EXECUTE. Запрос для курсора проверяется во время создания курсора, поэтому запрос не может быть динамическим.
Синтаксис SQL для подготовленных запросов не поддерживает многострочные запросы (то есть несколько запросов в одной строке, разделенных символами ;).
Для написания программ на языке C, которые используют SQL-запрос CALL для выполнения хранимых процедур, содержащих подготовленные запросы, необходимо включить флаг CLIENT_MULTI_RESULTS. Это связано с тем, что каждый CALL возвращает результат, указывающий на состояние вызова, помимо наборов результатов, которые могут быть возвращены запросами, выполненными внутри процедуры.
CLIENT_MULTI_RESULTS можно включить при вызове, либо явно, передавая флаг CLIENT_MULTI_RESULTS, либо неявно, передавая CLIENT_MULTI_STATEMENTS (что также включает CLIENT_MULTI_RESULTS). Дополнительную информацию см. в разделе 15.2.1, «Запрос CALL».
© 2025 Oracle
Licensed under the GPLv2 License.