Чтение онлайн

ЖАНРЫ

MySQL: руководство профессионала

Паутов Алексей В.

Шрифт:

Курсоры не сохраняются открытыми после передачи.

Курсоры не прокручиваемые.

Курсоры не именованы. Операторный драйвер действует как курсор ID.

Вы можете иметь открытым только один курсор на подготовленную инструкцию. Если Вы нуждаетесь в нескольких курсорах, Вы должны подготовить несколько инструкций.

Вы не можете использовать курсор для инструкции, которая генерирует набор результатов, если инструкция не обеспечивается в подготовленном режиме. Это включает инструкции типа 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, и не более эффективно, чем подзапрос.

Возможная будущая оптимизация: MySQL не переписывает порядок объединения для оценки подзапроса. В некоторых случаях подзапрос мог бы быть выполнен более эффективно, если MySQL переписал это как объединение. Это дало бы оптимизатору возможность, чтобы выбрать между большим количеством планов выполнения. Например, это могло бы решать, читать ли одну таблицу или другую первой:

SELECT a FROM outer_table AS ot

WHERE a IN (SELECT a FROM inner_table AS

it WHERE ot.b = it.b);

Поделиться с друзьями: