Оптимизация хранимых процедур Oracle - PullRequest
4 голосов
/ 03 февраля 2012

Недавно мне было поручено оптимизировать некоторые существующие хранимые процедуры Oracle.Каждая из хранимых процедур запрашивает базу данных и генерирует вывод файла XML.Один, в частности, занимал около 20 минут, чтобы закончить выполнение.Взглянув на это, было несколько вложенных циклов и ненужных запросов.Например, вместо

SELECT * from Employee e, Department d WHERE e.DEPT_ID = d.ID
--write data from query to XML

это было больше похоже на

FOR emp_rec in ( SELECT * from employee )
LOOP
   SELECT * from Department WHERE id = emp_rec.DEPT_ID;
   --write data from query to XML
END LOOP;

Изменение всех этих случаев, чтобы они больше походили на первый вариант, значительно ускорило процедуры.Мой вопрос почему?Почему объединение в запросе выбора быстрее, чем ручное объединение таблиц?Каковы основные процессы?

Ответы [ 2 ]

5 голосов
/ 03 февраля 2012

Давайте посмотрим, как, вероятно, будет обработана исходная версия.

FOR emp_rec in ( SELECT * from employee )
LOOP
   SELECT * from Department WHERE id = emp_rec.DEPT_ID;
   --write data from query to XML
END LOOP;

Запрос цикла может выполнить полное сканирование таблицы на employee.Затем для каждой возвращаемой строки будет выполнен внутренний запрос.Предполагая, что id является первичным ключом department, при каждом выполнении запроса может выполняться уникальный поиск с использованием индекса первичного ключа.

Звучит отлично, верно?Поиск по уникальному индексу обычно является самым быстрым способом получения одной строки (за исключением явного поиска по ROWID).Но подумайте о том, что это делает в течение нескольких итераций цикла.Предположительно, каждый сотрудник принадлежит к отделу;в каждом отделе есть сотрудники;и большинство или все отделы имеют несколько сотрудников.

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

Кроме того, в конечном итоге вы, вероятно, захотите каждую строку в department хотя бы один раз, а возможно, и более одного раза.Поскольку каждый отдельный блок в таблице нужно будет прочитать, вы на самом деле не экономите работу, выполняя поиск по индексу - вы добавляете работу.

Когда вы переписываете цикл как один запрос,оптимизатор может принять это во внимание.Один из возможных вариантов - объединение вложенных циклов, управляемое employee, что по сути будет таким же, как явный цикл в PL / SQL (за исключением переключения контекста, как было отмечено Марком).Однако, учитывая взаимосвязь между двумя таблицами и отсутствие каких-либо предикатов фильтрации, оптимизатор сможет сказать, что более эффективно просто выполнить полное сканирование обеих таблиц и выполнить слияние или хэш-соединение.На самом деле это приводит к меньшему количеству физических операций ввода-вывода (при условии, что в начале каждого выполнения выполняется очистка кэша) и гораздо меньшему количеству логических операций ввода-вывода.

4 голосов
/ 03 февраля 2012

«Базовые процессы» требуют большого ответа.Я уйду Том Кайт , чтобы ответить на этот вопрос;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...