WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
Обсуждение здесь описывает ограничения, которые относятся к использованию
свойств MySQL типа подзапросов или просмотров. Некоторые из ограничений, отмеченных здесь, относятся ко всем сохраненным
подпрограммам, то есть к сохраненным процедурам и сохраненным функциям.
Некоторые из ограничений применяются только к сохраненным функциям, но
не к сохраненным процедурам. Все ограничения для сохраненных функций
также относятся к триггерам. Сохраненные подпрограммы не могут содержать произвольные инструкции SQL.
Следующие инструкции отвергнуты: Инструкции блокировки Подготовленные инструкции SQL ( Для сохраненных функций (но не для процедур) следующие дополнительные
инструкции или операции отвергнуты: Инструкции, которые делают явный или неявный
commit или rollback. Инструкции, которые возвращают набор результатов. Это включает
инструкции Все инструкции Инструкции рекурсии. То есть, сохраненные функции не
могут использоваться рекурсивно. Внутри сохраненной функции или триггера не разрешается изменять
таблицу, которая уже используется (для чтения или записи) инструкцией,
которая вызвала функцию или триггер. Обратите внимание, что, хотя некоторые ограничения обычно относятся к
сохраненным функциям и триггерам, но не к сохраненным процедурам, эти
ограничения относятся к сохраненным процедурам, если они вызываются изнутри
сохраненной функции или триггера. Например, хотя Вы можете использовать
Тот же самый идентификатор можно использовать для стандартного параметра,
локальной переменной и столбца таблицы. Также, то же самое локальное
переменное имя может использоваться во вложенных блоках. Например: В таких случаях идентификатор неоднозначен, и следующие
правила старшинства применяются: Локальная переменная имеет приоритет над стандартным
параметром или столбцом таблицы. Стандартный параметр имеет приоритет над столбцом таблицы. Локальная переменная во внутреннем блоке имеет приоритет над
локальной переменной во внешнем блоке. Поведение, что столбцы таблицы не имеют приоритет
над переменными, ненормативно. Использование сохраненных подпрограмм может вызывать проблемы
дублирования. Эта проблема рассмотрена далее. Не имеется никакой системы отладки сохраненных подпрограмм. Инструкции Драйверы Циклы Чтобы предотвращать проблемы взаимодействия между потоками сервера, когда
пользователь выдает инструкцию, сервер использует кадр подпрограмм и вызывает
доступные для выполнения инструкции. То есть, сервер вычисляет список
процедур, функций и триггеров, который может использоваться в течение
выполнения инструкции, загружает их, и затем продолжает выполнять инструкцию.
Это означает, что, в то время как инструкция выполняется, она не будет видеть
изменения для подпрограмм, выполняемых другими потоками сервера. Инструкция Для триггеров следующие дополнительные инструкции или операции отвергнуты:
Триггеры в настоящее время не активизированы
действиями внешнего ключа. Инструкция Триггеры не позволяются на таблицах в базе данных Курсоры стороны сервера выполнены в C API через функцию
В MySQL серверные курсоры осуществлены сквозь временную таблицу.
Первоначально это таблица Курсоры предназначены пока только для чтения: Вы не можете использовать
курсор, чтобы модифицировать строки. А поэтому обновляемые курсоры не
обеспечиваются. Следовательно, Курсоры не сохраняются открытыми после передачи. Курсоры не прокручиваемые. Курсоры не именованы. Операторный драйвер действует как курсор ID. Вы можете иметь открытым только один курсор на подготовленную инструкцию.
Если Вы нуждаетесь в нескольких курсорах,
Вы должны подготовить несколько инструкций. Вы не можете использовать курсор для инструкции, которая генерирует набор
результатов, если инструкция не обеспечивается в подготовленном режиме. Это
включает инструкции типа Известная ошибка, которая будет фиксирована позже:
если Вы сравниваете значение Внешняя инструкция подзапроса может быть любой из
Оптимизация подзапроса для Типичный случай для недостаточной эффективности подзапроса
Проблема состоит в том, что для инструкции, которая использует в
подзапросе Оптимизатор переписывает инструкцию к соотнесенному подзапросу: Если внутренние и внешние запросы возвращают
Подзапрос Вообще, Вы не можете изменять таблицу и выбирать из той же самой
таблицы в подзапросе. Например, это ограничение применяется к
инструкциям следующих форм: Исключительная ситуация: предшествующее запрещение не применяется, если Вы
используете подзапрос для изменяемой таблицы в
предложении Здесь запрещение не применяется, потому что результат от подзапроса в
предложении Операции сравнения строк обеспечиваются пока только частично:
Для Для Другими словами, для подзапроса, который возвращает строки
Но это не обеспечивается: Причина для обеспечения сравнений строки для Конструкторы строк не оптимизированы хорошо. Следующие два выражения
эквивалентны, но только второе может быть оптимизировано: Подзапросы в предложении Оптимизатор более отлажен для объединений, чем для подзапросов, так
что во многих случаях инструкция, применяющая подзапрос, может быть выполнена
более эффективно, если Вы переписываете это как объединение. Исключительная ситуация происходит для случая, где подзапрос
Эта инструкция может быть переписана следующим образом: Но в этом случае объединение требует операции Возможная будущая оптимизация: MySQL не переписывает порядок
объединения для оценки подзапроса. В некоторых случаях подзапрос мог бы быть
выполнен более эффективно, если MySQL переписал это как объединение. Это дало
бы оптимизатору возможность, чтобы выбрать между большим количеством планов
выполнения. Например, это могло бы решать, читать ли одну таблицу
или другую первой: Для этого запроса MySQL всегда просматривает сначала
Предшествующий запрос мог бы быть переписан подобно этому: В этом случае мы можем просматривать маленькую таблицу
( Возможная будущая оптимизация: соотнесенный подзапрос оценен для
каждой строки внешнего запроса. Лучший подход: если внешние значения строки
не изменяются с предыдущей строки, чтобы не оценивать подзапрос снова. Вместо
этого, используется предыдущий результат. Возможная будущая оптимизация: подзапрос в предложении
Возможная будущая оптимизация: если подзапрос в предложении
Инструкция может быть переписана как объединение подобно этому: Этот тип перезаписи обеспечил бы две выгоды: Это избегает использования временной таблицы, для
которой никакие индексы не могут использоваться. В переписанном запросе
оптимизатор может использовать индексы на Это дает оптимизатору большее количество свободы выбрать между
различными планами выполнения. Например, перезапись запроса как объединения
позволяет оптимизатору использовать сначала
Возможная будущая оптимизация: для В этом случае мы могли бы создавать временную таблицу: Затем для каждой строки в Обработка View не оптимизирована: Невозможно создать индекс на view. Индексы могут использоваться для обработанных view, используя
объединяющий алгоритм. Однако, view, который обработан алгоритмом temptable,
не способен пользоваться преимуществом индексов на основных таблицах (хотя
индексы могут использоваться в течение поколения временных таблиц).
Подзапросы не могут использоваться в предложении Имеется общий принцип, что Вы не можете изменять таблицу и выбирать из той
же самой таблицы в подзапросе. Тот же самый принцип также применяется, если Вы выбираете из view, который
выбирает из таблицы, если выбор view из таблицы в подзапросе и view оценены,
используя объединяющий алгоритм. Пример: Если view оценен, используя временную таблицу, Вы можете выбирать из
таблицы в view подзапросом и менятт ту таблицу во внешнем запросе. В этом
случае view будет сохранен во временной таблице, и таким образом Вы
действительно не выбираете из таблицы в подзапросе и изменяете таблицу в то
же самое время. Можно принудительно предписать MySQL использовать алгоритм
temptable, определяя Вы можете использовать Определение view заморожено некоторыми инструкциями: Если инструкция, подготовленная Результат, возвращенный инструкцией Если инструкция в сохраненной подпрограмме обращается к view,
содержание view точно такое же, как в первый раз, когда инструкция выполнена.
Например, это означает, что, если инструкция выполнена в цикле, дальнейшие
итерации инструкции видят то же самое содержание view, даже если определение
view изменено позже в цикле. Пример: Когда процедура Относительно обновляемых view: полная цель для view состоит в том, что,
если любой view является теоретически обновляемым, это должно быть
обновляемым и практически. Это включает view, которые имеют
Обновляемые view с подзапросами где-нибудь не в
предложении Вы не можете использовать Вы не можете использовать Если пользователю предоставляют базисные привилегии, необходимые, чтобы
создавать view (привилегии Этот недостаток может привести к проблемам при копировании базы данных с
помощью mysqldump, которая
может терпеть неудачу из-за недостаточных привилегий. Эта проблема описана в
Глюке #22062. Обход: чтобы администратор вручную предоставил привилегию Максимальное число таблиц, которые могут быть названы в одиночном
объединении, составляет 61. Это также применяется к числу таблиц, которые
могут быть названы в определении view.
Глава 11. Ограничения свойств
11.1. Ограничения на сохраненные
подпрограммы и триггеры
LOCK TABLES
и
UNLOCK TABLES
.LOAD DATA
и LOAD TABLE
.PREPARE
,
EXECUTE
, DEALLOCATE PREPARE
). Вы не можете
использовать динамический SQL внутри сохраненных подпрограмм (где Вы создаете
динамически инструкции как строки, а затем выполняете их). Это ограничение
снимается в MySQL 5.0.13 для сохраненных процедур, но это все еще применяется
к сохраненным функциям и триггерам.SELECT
, которые не имеют предложения
INTO
, и инструкции
var_list
SHOW
. Функция может обрабатывать набор результатов через
SELECT ... INTO
или используя
курсор и инструкции var_list
FETCH
.FLUSH
.FLUSH
в сохраненной процедуре, такая сохраненная процедура не
может быть вызвана из сохраненной функции или из триггера.
CREATE PROCEDURE p (i INT)
BEGIN
DECLARE i INT DEFAULT 0;
SELECT i FROM t;
BEGIN
DECLARE i INT DEFAULT 1;
SELECT i FROM t;
END;
END;
INFORMATION_SCHEMA
еще не имеет таблицу
PARAMETERS
, так что прикладные программы, которым надо собирать
стандартную информацию параметров во время выполнения должны использовать
методы типа синтаксического анализа вывода
инструкций SHOW CREATE
.CALL
не могут быть подготовлены.UNDO
не обеспечиваются.FOR
не обеспечиваются.RENAME DATABASE
не перемещает сохраненные
подпрограммы к новому имени схемы.RETURN
запрещена в триггере, который не может
возвращать значение. Чтобы выходить из него немедленно,
используйте инструкцию LEAVE
.mysql
.
11.2. Ограничения на курсоры сервера
mysql_stmt_attr_set()
. Та же самая реализация используется для
курсоров в сохраненных подпрограммах. Курсор стороны сервера позволяет набору
результатов быть сгенерированным на стороне сервера, но не перемещен
пользователю, кроме тех строк, которые пользователь запрашивает. Например,
если пользователь выполняет запрос, но заинтересован только первой строкой,
остающиеся строки не будут перемещены.MEMORY
, но преобразованная в таблицу
MyISAM
, если размер достигает значения переменной системы
max_heap_table_size
. Одно ограничение реализации в том, что для
большого набора результатов получение строк через курсор
может быть медленным.UPDATE WHERE CURRENT OF
и
DELETE WHERE CURRENT OF
не выполнены.CHECK TABLES
,
HANDLER READ
и SHOW BINLOG EVENTS
.11.3. Ограничения на подзапросы
NULL
с подзапросом, использующим
ALL
, ANY
или SOME
, и подзапрос
возвращают пустой результат, сравнение может быть оценено к ненормативному
результату NULL
, а не к TRUE
или FALSE
.
SELECT
, INSERT
, UPDATE
,
DELETE
, SET
или DO
.IN
не как эффективна, как для
оператора =
или для конструкции
IN(
.value_list
)IN
: когда подзапрос возвращает маленькое число строк, но внешний
запрос возвращает большое количество строк, которые нужно
сравнить с результатом подзапроса.IN
, оптимизатор перезаписывает это как соотнесенный
подзапрос. Рассмотрите следующую инструкцию, которая
использует несоотнесенный подзапрос:
SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);
M
и N
строк соответственно, время
выполнения становится порядка
O(
, а не
M
^N
)O(
, как это было
бы для несоотнесенного подзапроса.M
+N
)IN
может быть намного медленнее, чем запрос,
написанный с использованием конструкции
IN(
, которая вносит в список те
же самые значения, которые возвратил бы подзапрос.value_list
)
DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);
FROM
. Пример:
UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);
FROM
сохранен как временная таблица, так что
релевантные строки в t
уже были выбраны
ко времени модификации t
.
, expr
IN
(subquery
)expr
может быть n
-кортеж (определенный через синтаксис
конструктора строки) и подзапрос может
возвращать строки n
-кортежей.
, expr
op
{ALL|ANY|SOME}
(подзапрос
)expr
должен быть скалярным значением, и подзапрос должен быть подзапросом столбца,
это не может возвращать строки с многими столбцами.n
-кортежей, это обеспечивается:
(
val_1
, ..., val_n
) IN
(subquery
)
(
val_1
, ..., val_n
)
op
{ALL|ANY|SOME} (subquery
)
IN
, но не для
других: IN
выполнен, перезаписывая это как последовательность
сравнений =
и операций AND
. Этот подход не может
использоваться для ALL
, ANY
или SOME
.
(col1, col2, ...) = (val1, val2, ...)
col1 = val1 AND col2 = val2 AND ...
FROM
не могут быть соотнесены
подзапросам. Они осуществлены (выполнены, чтобы произвести набор результатов)
перед оценкой внешнего запроса, так что они не могут быть оценены на
строку внешнего запроса.IN
может быть переписан как объединение
SELECT DISTINCT
. Пример:
SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE
condition
);
SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND
condition
;
DISTINCT
, и не
более эффективно, чем подзапрос.
SELECT a FROM outer_table AS ot
WHERE a IN (SELECT a FROM inner_table AS
it WHERE ot.b = it.b);
outer_table
, а затем выполняет подзапрос на
inner_table
для каждой строки. Если outer_table
имеет много строк, и inner_table
имеет немного строк, запрос,
вероятно, не будет работать с такой скоростью как могло бы быть.
SELECT a FROM outer_table AS ot, inner_table AS it
WHERE ot.a = it.a AND
ot.b = it.b;
inner_table
) и искать строки в outer_table
, что
будет быстро, если имеется индекс на (ot.a,ot.b)
.FROM
оценен, осуществляя результат во временную таблицу, и эта
таблица не использует индексы. Это не позволяет использование индексов по
сравнению с другими таблицами в запросе, хотя это могло бы быть полезно.
FROM
походит на просмотр, к которому может применяться
объединяющийся алгоритм, переписать запрос и применить объединяющийся
алгоритм так, чтобы индексы могли использоваться. Следующая инструкция
содержит такой подзапрос:
SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;
SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;
t1
.t1
или t2
.IN
,
= ANY
, <> ANY
, = ALL
и
<> ALL
с не соотнесенными подзапросами использовать в
оперативной памяти хэш для результата или временную таблицу с индексом для
больших результатов. Пример:
SELECT a FROM big_table AS bt WHERE non_key_field IN
(SELECT non_key_field FROM
table
WHERE
condition
)
CREATE TABLE t (key (non_key_field))
(SELECT non_key_field FROM
table
WHERE
condition
)
big_table
сделайте поисковую
таблицу ключа в t
, основываясь на bt.non_key_field
.
11.4. Ограничения на Views
FROM
view.
Это ограничение будет сниматься в будущем.
CREATE VIEW v1 AS SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE
t1.a = t2.a);
UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;
ALGORITHM = TEMPTABLE
в определении view.
DROP TABLE
или ALTER
TABLE
, чтобы удалять или изменять таблицу, которая используется в
определении view (это объявляет неверным view), и никакого предупреждения не
последует. Ошибка происходит позже, когда view используется.PREPARE
,
обращается к view, то содержание этого view какждый раз при выполнении
инструкции будет точно соответствовать моменту ее подготовки. Это истинно,
даже если определение view изменен после того, как инструкция подготовлена,
но прежде, чем она выполнена. Пример:
CREATE VIEW v AS SELECT 1;
PREPARE s FROM 'SELECT * FROM v';
ALTER VIEW v AS SELECT 2;
EXECUTE s;
EXECUTE
, 1, а не 2.
CREATE VIEW v AS SELECT 1;
delimiter //
CREATE PROCEDURE p ()
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i < 5 DO
SELECT * FROM v;
SET i = i + 1;
ALTER VIEW v AS SELECT 2;
END WHILE;
END;
//
delimiter ;
CALL p();
p()
вызвана, SELECT
возвращает
1 каждый раз в цикле, даже при том, что определение view
изменено внутри цикла.UNION
в их определении. В настоящее время не все просмотры,
которые являются теоретически обновляемыми, таковы на деле (могут
модифицироваться). Начальная реализация view была преднамеренно написана этим
способом, чтобы стать пригодной для использования, обновляемые view в MySQL
будут сделаны настолько быстро, насколько возможно. Многие теоретически
обновляемые view могут модифицироваться теперь, но ограничения
все еще существуют:WHERE
. Некоторые view, которые имеют подзапросы в
списке SELECT
, могут быть обновляемыми.UPDATE
, чтобы модифицировать
больше, чем одну основную таблицу view, который определен как объединение.
DELETE
, чтобы модифицировать
view, который определен как объединение.CREATE VIEW
и SELECT
),
этот пользователь будут не способен вызвать SHOW CREATE VIEW
на этом объекте, если пользователю не предоставляют
также привилегию SHOW VIEW
.SHOW
VIEW
пользователям, которым предоставляется CREATE VIEW
,
так как MySQL не предоставляет это неявно, когда создан view.11.5. Ограничения на Join
Найди своих коллег! |