Давайте посмотрим, как будет обрабатываться исходная версия.
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 (минус переключение контекста, как указано Mark). Однако, учитывая отношения между двумя таблицами и отсутствие предиката фильтрации, оптимизатор сможет сказать, что более эффективно просто полностью сканировать обе таблицы и объединить объединение или хеш-соединение. Это фактически приводит к меньшему количеству физических IO (предполагая чистый кэш в начале каждого выполнения) и значительно меньшее количество логических IO.
Хороший ответ. И лучший ответ, чем я предусмотрел ... :-) –