четверг, 15 ноября 2012 г.

Немного о временных таблицах

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

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

Привыкнув к такому положению вещей, очень легко упустить одну важную деталь.
Предположим, у нас очень сложный отчет, для реализации блока данных которого практически невозможно обойтись одним всеобъемлющим SQL-запросом. Поэтому в таких случаях и используют временные таблицы, сохраняя в них промежуточные данные, по которым строится итоговая выборка. Часто можно встретить код, представляющий такую последовательность действий:
  1. Заполнить временную таблицу очень большим объемом данных
  2. Собрать статистику по этой таблице
  3. Использовать эту таблицу в дальнейших очень сложных запросах 
Казалось бы, все логично, однако что представляет собой сбор статистики? По сути это DDL-операция, а значит, она блокирует весь объект. Но ведь это же временная таблица, спросите вы? Значит и сбор статистики должен выполняться отдельно от всех сессий? Для Oracle нет разницы, какого рода DDL операцию вы совершаете - добавляете в таблицу столбец или собираете статистику. Поэтому, в отличие от данных временной таблицы, ее статистика:
  • Собирается для всей таблицы и становится актуальной во всех сессиях. То есть, заполнив временную таблицу определенным образом и собрав статистику актуальную лишь для текущей сессии, мы навязываем ее другим (параллельным или последующим) сессиям, вводя их в заблуждение
  • При сборе создает блокировку, мешающую другим сессиям. Это приводит к проблемам с производительностью в случае параллельного запуска отчета - процессы могут выстраиваться в очередь из-за блокировки временной таблицы
Как же быть в том случае если данных во временной таблице действительно очень много и необходимость сбора статистики напрашивается сама собой? На помощь приходит механизм dynamic sampling. С его помощью  статистика по требуемой таблице собирается прямо в ходе выполнения запроса и больше нигде не используется. Включить его для отдельно взятой таблицы можно посредством хинта /*+ dynamic_sampling({table_name} {level}) */. Значение level указывает, насколько полной должна быть статистика (0 - никакой статистики, 10 - полная статистика).

Вообще говоря, бессмысленность статического сбора статистики по временной таблице не осталась незамеченной разработчиками СУБД Oracle, поэтому, скажем, операция analyze для временных таблиц недоступна. Однако, никто не мешает осуществить вызов dbms_stats.gather_table_stats (или fnd_stats.gather_table_stats в системе OeBS). Это послужило определенного рода ловушкой - наличие подобных вызовов в коде не является редкостью.





Комментариев нет:

Отправить комментарий