Хранимая процедура Oracle, возвращающая курсор ref против ассоциативных массивов - PullRequest
1 голос
/ 09 марта 2012

Наш администратор БД требует, чтобы мы возвращали все табличные данные из хранимых процедур в виде набора ассоциативных массивов, а не с помощью курсора ref, который я вижу в большинстве примеров в Интернете.Он говорит, что это связано с тем, что Oracle делает это намного быстрее, но мне кажется, что это противоречит интуитивному пониманию, потому что данные необходимо циклически повторять дважды, один раз в хранимой процедуре, а затем снова в приложении, когда оно обрабатывается.Кроме того, значения часто должны быть преобразованы из их собственных типов в varchar, чтобы их можно было сохранить в массиве и затем вернуть обратно на стороне приложения.Использование этого метода также затрудняет использование инструментов orm, потому что в большинстве случаев они нуждаются в ref-курсорах.

Пример хранимой процедуры:

PROCEDURE sample_procedure (
                                p_One       OUT varchar_array_type,
                                p_Two       OUT varchar_array_type,
                                p_Three     OUT varchar_array_type,
                                p_Four      OUT varchar_array_type
                            )
IS
p_title_procedure_name        VARCHAR2(100) := 'sample_procedure';
v_start_time DATE :=SYSDATE;    

CURSOR cur
  IS
    SELECT e.one, e.two, e.three, e.four FROM package.table 
    WHERE filter='something';

    v_counter PLS_INTEGER := 0;
BEGIN

    FOR rec IN cur LOOP
        BEGIN
            v_counter := v_counter + 1;
            p_One(v_counter) := rec.one;
            p_Two(v_counter) := rec.two;
            p_Three(v_counter) := rec.three;
            p_Four(v_counter) := rec.four;
        END;
    END LOOP;
END;

Курсориспользуется для заполнения одного массива для каждого возвращаемого столбца.Я пытался найти информацию, подтверждающую его утверждение, что этот метод быстрее, но не смог этого сделать.Может кто-нибудь объяснить мне, почему он может захотеть, чтобы мы (разработчики .net) писали хранимые процедуры таким образом?

Ответы [ 2 ]

12 голосов
/ 09 марта 2012

Запрос администратора базы данных не имеет смысла.

Администратор почти наверняка думает о том, что он хочет минимизировать количество сдвигов контекста механизма SQL в PL / SQL, которые происходят при извлечении данных.от курсора.Но предлагаемое решение плохо нацелено на эту конкретную проблему и создает другие гораздо более серьезные проблемы с производительностью в большинстве систем.

В Oracle смещение контекста с SQL на PL / SQL происходит, когда виртуальная машина PL / SQLзапрашивает у виртуальной машины SQL дополнительные данные, виртуальная машина SQL отвечает, выполняя оператор, чтобы получить данные, которые затем упаковывает и передает обратно в виртуальную машину PL / SQL.Если подсистема PL / SQL запрашивает строки по одной за раз, и вы извлекаете много строк, возможно, что эти сдвиги контекста могут составлять значительную долю вашего общего времени выполнения.Для решения этой проблемы Oracle ввела концепцию массовых операций, по крайней мере, в течение 8 дней.Это позволило виртуальной машине PL / SQL запрашивать несколько строк одновременно с виртуальной машины SQL.Если виртуальная машина PL / SQL запрашивает 100 строк за раз, вы устранили 99% сдвигов контекста, и ваш код потенциально может работать намного быстрее.

После введения массовых операций появилось много кода, которыйможет быть реорганизован для повышения эффективности путем явного использования операций BULK COLLECT вместо выборки построчно и последующего использования циклов FORALL для обработки данных в этих коллекциях.Однако к 10.2 дням Oracle объединила массовые операции в неявные циклы FOR, поэтому неявный цикл FOR теперь автоматически массово собирает пакеты по 100, а не извлекает строку за строкой.

В вашемОднако в этом случае, поскольку вы возвращаете данные клиентскому приложению, использование массовых операций гораздо менее значимо.Любой достойный API на стороне клиента будет иметь функциональность, позволяющую клиенту указывать, сколько строк нужно извлечь из курсора в каждом цикле обхода сети, и эти запросы на выборку будут идти непосредственно на виртуальную машину SQL, а не через PL/ SQL VM, поэтому нет никаких сдвигов контекста SQL в PL / SQL, о которых стоит беспокоиться.Ваше приложение должно заботиться о получении соответствующего количества строк в каждом цикле - достаточно, чтобы приложение не становилось слишком болтливым и узким местом в сети, но не настолько, чтобы вам приходилось слишком долго ждать, пока результаты не будутвозвращено или для хранения слишком большого объема данных в памяти.

Возврат коллекций PL / SQL, а не REF CURSOR, в клиентское приложение не приведет к уменьшению количества происходящих изменений контекста.Но у него будет множество других недостатков, не последним из которых является использование памяти.Коллекция PL / SQL должна храниться целиком в глобальной области процесса (PGA) (при условии подключения к выделенному серверу) на сервере базы данных.Это кусок памяти, который должен быть выделен из оперативной памяти сервера.Это означает, что серверу нужно будет выделить память для выборки каждой последней строки, которую запрашивает каждый клиент.Это, в свою очередь, резко ограничит масштабируемость вашего приложения и, в зависимости от конфигурации базы данных, может украсть ОЗУ из других частей базы данных Oracle, что будет очень полезно для повышения производительности приложений.И если у вас закончится пространство PGA, ваши сеансы начнут получать ошибки, связанные с памятью.Даже в приложениях, основанных исключительно на PL / SQL, вы никогда не захотите извлекать все данные в коллекции, вам всегда нужно извлекать их небольшими партиями, чтобы минимизировать количество используемой PGA.

Кроме того, загрузка всех данных в память заставит приложение работать намного медленнее. Практически любой фреймворк позволит вам извлекать данные по мере необходимости, например, если у вас есть отчет, отображаемый на страницах по 25 строк каждая, вашему приложению потребуется только извлечь первые 25 строк, прежде чем рисовать первый экран. И ему никогда не придется выбирать следующие 25 строк, если пользователь случайно не запросит следующую страницу результатов. Однако, если вы извлекаете данные в массивы, как предлагает ваш администратор базы данных, вам придется извлечь все строки, прежде чем приложение сможет начать отображать первую строку, даже если пользователь никогда не хочет видеть больше, чем первая горстка строк. Это будет означать гораздо больше операций ввода-вывода на сервере базы данных для извлечения всех строк, больше PGA на сервере, больше оперативной памяти на сервере приложений для буферизации результата и более длительное ожидание сети.

0 голосов
/ 09 марта 2012

Я считаю, что Oracle начнет отправлять результаты из системы, подобной этой, по мере сканирования базы данных, а не извлекать их все и затем отправлять обратно. Это означает, что результаты отправляются по мере их обнаружения, что ускоряет работу системы. (На самом деле, если я правильно помню, он возвращает результаты в цикле.) Это в основном из памяти какой-то тренировки

ОДНАКО, реальный вопрос, почему бы не спросить его прямо. Возможно, он ссылается на уловку, которую может использовать Oracle, и если вы понимаете специфику, вы можете использовать уловку скорости, чтобы использовать ее весь потенциал. Как правило, предельное «Всегда делай это, так как это быстрее» вызывает подозрение и заслуживает более пристального взгляда, чтобы полностью понять их намерения. Могут быть ситуации, когда это действительно неприменимо (например, небольшие результаты запроса), когда все проблемы с читаемостью и накладные расходы не влияют на производительность.

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

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