Spec-Zone.ru › MySQL 5.7

8.2.2.4 Оптимизация производных таблиц и ссылок на представления с помощью слияния или материализации

Оптимизатор может обрабатывать ссылки на производные таблицы, используя два подхода (которые также применимы к ссылкам на представления):

  • Слить производную таблицу в основной блок запроса

  • Материализовать производную таблицу в внутреннюю временную таблицу

Пример 1:

SELECT * FROM (SELECT * FROM t1) AS derived_t1;

При слиянии производной таблицы derived_t1, запрос выполняется аналогично:

SELECT * FROM t1;

Пример 2:

SELECT *
  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1
  WHERE t1.f1 > 0;

При слиянии производной таблицы derived_t2, запрос выполняется аналогично:

SELECT t1.*, t2.f1
  FROM t1 JOIN t2 ON t1.f2=t2.f1
  WHERE t1.f1 > 0;

При материализации, derived_t1 и derived_t2 рассматриваются как отдельные таблицы в своих соответствующих запросах.

Оптимизатор обрабатывает производные таблицы и ссылки на представления одинаково: он избегает ненужной материализации всякий раз, когда это возможно, что позволяет продвигать условия из основного запроса в производные таблицы и создавать более эффективные планы выполнения. (См. Раздел 8.2.2.2, «Оптимизация подзапросов с материализацией».)

Если слияние приведет к основному блоку запроса, который ссылается на более чем 61 базу таблиц, оптимизатор выбирает материализацию вместо этого.

Оптимизатор распространяет предложение ORDER BY в производной таблице или ссылке на представление на основной блок запроса, если все эти условия выполняются:

  • Основной запрос не сгруппирован и не агрегирован.

  • Основной запрос не указывает DISTINCT, HAVING или ORDER BY.

  • Основной запрос имеет эту производную таблицу или ссылку на представление как единственный источник в предложении FROM.

В противном случае оптимизатор игнорирует предложение ORDER BY.

Доступны следующие способы влияния на то, пытается ли оптимизатор слить производные таблицы и ссылки на представления в основной блок запроса:

  • Флаг derived_merge системной переменной optimizer_switch может быть использован, предполагая, что другие правила не препятствуют слиянию. См. Раздел 8.9.2, «Переключаемые оптимизации». По умолчанию, флаг включен для разрешения слияния. Отключение флага предотвращает слияние и избегает ошибок.

    Флаг derived_merge также относится к представлениям, не содержащим предложения ALGORITHM. Таким образом, если возникает ошибка для ссылки на представление, использующей выражение, эквивалентное подзапросу, добавление ALGORITHM=TEMPTABLE в определение представления предотвращает слияние и имеет приоритет над значением derived_merge.

  • Можно отключить слияние, используя в подзапросе любые конструкции, которые препятствуют слиянию, хотя они не так явны в своем влиянии на материализацию. Конструкции, которые препятствуют слиянию, одинаковы для производных таблиц и ссылок на представления:

    • Агрегатные функции (SUM(), MIN(), MAX(), COUNT() и т.д.)

    • DISTINCT

    • GROUP BY

    • HAVING

    • LIMIT

    • UNION или UNION ALL

    • Подзапросы в списке выбора

    • Присваивания переменным пользователя

    • Ссылки только на литеральные значения (в этом случае нет базовой таблицы)

Флаг derived_merge также относится к представлениям, не содержащим предложения ALGORITHM. Таким образом, если возникает ошибка для ссылки на представление, использующей выражение, эквивалентное подзапросу, добавление ALGORITHM=TEMPTABLE в определение представления предотвращает слияние и имеет приоритет над текущим значением derived_merge.

Если оптимизатор выбирает стратегию материализации вместо слияния для производной таблицы, он обрабатывает запрос следующим образом:

  • Оптимизатор откладывает материализацию производной таблицы до тех пор, пока ее содержимое не потребуется во время выполнения запроса. Это улучшает производительность, потому что отложенная материализация может привести к тому, что ее вообще не придется выполнять. Рассмотрим запрос, который объединяет результат производной таблицы с другой таблицей: если оптимизатор сначала обработает другую таблицу и обнаружит, что она возвращает 0 строк, объединение не нужно выполнять дальше, и оптимизатор может полностью пропустить материализацию производной таблицы.

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

Рассмотрим следующее предложение EXPLAIN для запроса SELECT, который содержит производную таблицу:

EXPLAIN SELECT * FROM (SELECT * FROM t1) AS derived_t1;

Оптимизатор избегает материализации производной таблицы, откладывая ее до тех пор, пока результат не потребуется во время выполнения SELECT. В этом случае запрос не выполняется (потому что он выполняется в предложении EXPLAIN), поэтому результат никогда не нужен.

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

SELECT *
  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2
          ON t1.f2=derived_t2.f1
  WHERE t1.f1 > 0;

Если оптимизация обрабатывает t1 сначала, и предложение WHERE создает пустой результат, объединение обязательно будет пустым, и производная таблица не должна материализовываться.

В случаях, когда для производной таблицы требуется материализация, оптимизатор может добавить индекс к материализованной таблице для ускорения доступа к ней. Если такой индекс позволяет использовать доступ ref к таблице, он может значительно сократить количество считываемых данных во время выполнения запроса. Рассмотрим следующий запрос:

SELECT *
 FROM t1 JOIN (SELECT DISTINCT f1 FROM t2) AS derived_t2
         ON t1.f1=derived_t2.f1;

Оптимизатор создает индекс по столбцу f1 из derived_t2, если это позволит использовать доступ ref для плана выполнения с наименьшей стоимостью. После добавления индекса оптимизатор может рассматривать материализованную производную таблицу так же, как обычную таблицу с индексом, и он аналогично выигрывает от сгенерированного индекса. Накладные расходы на создание индекса незначительны по сравнению со стоимостью выполнения запроса без индекса. Если доступ ref приведет к более высокой стоимости, чем какой-либо другой метод доступа, оптимизатор не создает индекс и не теряет ничего.

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

© 2025 Oracle
Licensed under the GPLv2 License.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/derived-table-optimization.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API