Почему PLSQL медленнее, чем SQL*Plus

Это хорошее время, чтобы узнать, что такое xvalues ​​ и glvalues ​​.

R-значения могут быть двух типов - , значения и , значения . В соответствии с новым стандартом C ++ 17

prvalue - это выражение, вычисление которого инициализирует объект, битовое поле или операнд оператора, как указано в контексте в котором оно появляется.

, поэтому что-то вроде fun() в вашем примере оценивается как prvalue (который является r-значением). Это также говорит нам, что fun().v не является prvalue, так как это не ванильная инициализация.

X-значения , которые также являются r-значениями, определяются так

xvalue (значение «eXpiring») также относится к объекту обычно ближе к концу срока службы (например, ресурсы можно переместить). Определенные виды выражений, включающие ссылки на rvalue (8.3.2), дают значения xvalue. [Пример: Результатом вызова функции, возвращаемый тип которой является rvalue-ссылкой на тип объекта, является xvalue (5.2.2). - конец примера]

В дополнение к rvalues, еще одной зонтичной категорией значений является glvalue , которые бывают двух типов xvalues ​​ и традиционные lvalues .

На данный момент мы определили категории основных значений. Это может быть визуализировано следующим образом

enter image description here

Категория glvalue может широко означать, что lvalues должны были означать до того, как семантика перемещения стала вещью - вещью, которая может быть в левой части выражения. glvalue означает обобщенное lvalue.

Если мы посмотрим на определение значения xvalue , то оно говорит, что что-то является значением xvalue , если оно подходит к концу своего времени жизни. В вашем примере, fun().v подходит к концу своего времени жизни. Таким образом, его ресурсы могут быть перемещены. И поскольку его ресурсы можно перемещать, это не lvalue, поэтому ваше выражение вписывается в единственную оставшуюся категорию значений листьев - xvalue .

6
задан Brad Bruce 6 November 2009 в 16:23
поделиться

6 ответов

Используйте трассировку SQL, чтобы увидеть, каковы планы выполнения в каждом случае. Одна возможность, которая приходит на ум (исходя из опыта): связывает ли пакет с запросом неверный тип значений? Возможно, в SQL Plus вы выполняете:

select * from mytable where id = '1234';

, но в PL / SQL вы выполняете:

select * from mytable where id = p_id;

, где p_id определяется как число. Это приведет к принудительному использованию TO_NUMBER в столбце идентификатора и предотвратит использование индекса Oracle.

9
ответ дан 8 December 2019 в 14:44
поделиться

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

Когда вы обрабатываете результаты запроса в ] PL / SQL , происходит переключение контекста. Он требует передачи большого количества данных между процессами Oracle и выполняется довольно медленно.

Как этот код:

DECLARE
        cnt INTEGER := 0;
        CURSOR  cr_main IS
        SELECT  1 AS id
        FROM    dual
        CONNECT BY
                level <= 1000000;
BEGIN
        FOR res IN cr_main
        LOOP
                cnt := cnt + res.id;
        END LOOP;
        DBMS_OUTPUT.put_line(cnt);
END;

выполняется на моей машине более 3 секунд, а этот :

SELECT  SUM(1)
FROM    dual
CONNECT BY
        level <= 1000000

завершается всего за 0,5 секунды.

Переключение контекста также происходит при вызове PL / SQL из SQL , например:

SELECT  plsql_function(column)
FROM    mytable

] или при срабатывании триггера.

3
ответ дан 8 December 2019 в 14:44
поделиться

Наш администратор баз данных наблюдал, что эти запросы занимают 10 минут через PLSQL и 10 секунд через PL / PSQL .

Я могу понять, если администратор базы данных не захочет решать эту проблему за вас, но если ваш администратор базы данных действительно видел оба случая и еще не предоставил вам планы объяснения для обоих случаев, тогда он действительно не очень хороший администратор базы данных. .

Вероятно, нет неправильной конфигурации, я сам такое случалось - все связываемые переменные, никаких констант, никаких подсказок. Запускать напрямую - производительность хорошая. Поместите его внутрь BEGIN..END - бац, чертовски медленно. Оказалось, что иногда запросы просто используют разные планы выполнения из PL / SQL (это был Oracle 9.2).

Мое решение - использовал подсказки, пока версия PL / SQL не использовала тот же план, что и SQL. так строки, а затем ждет, когда вы попросите больше, но PL / SQL должен обрабатывать их всех, не спрашивая. Тривиальная проблема, но иногда ее забывают.

  • Вы используете константы для SQL * Plus и связываете переменные для PL / SQL. Иногда использование констант позволяет оптимизатору проверять искаженные данные, и он может использовать какой-либо другой индекс.
  • 2
    ответ дан 8 December 2019 в 14:44
    поделиться

    Если вы работаете в Windows, я рекомендую использовать глобальный уникальный идентификатор (GUID) в качестве идентификатор версии.

    Отметка времени (даже если UTC) может вызвать проблемы, если часы установлены пользователем. Увеличивающееся число (если оно хранится в памяти) может вызвать проблемы при перезапуске серверного приложения или его переполнении (если это всего лишь 16-битное или 32-битное целое число).

    Он требует передачи большого количества данных между процессами Oracle и выполняется довольно медленно.

    Как этот код:

    DECLARE
            cnt INTEGER := 0;
            CURSOR  cr_main IS
            SELECT  1 AS id
            FROM    dual
            CONNECT BY
                    level <= 1000000;
    BEGIN
            FOR res IN cr_main
            LOOP
                    cnt := cnt + res.id;
            END LOOP;
            DBMS_OUTPUT.put_line(cnt);
    END;
    

    выполняется более 3 секунд на моей машине, а этот:

    SELECT  SUM(1)
    FROM    dual
    CONNECT BY
            level <= 1000000
    

    завершается всего за 0,5 секунды.

    ] Переключение контекста также происходит, когда вы вызываете PL / SQL из SQL, например:

    SELECT  plsql_function(column)
    FROM    mytable
    or when a trigger fires.
    

    Одним из способов решения проблемы переключения контекста является использование BULK COLLECT. Если вы собираете много строк, использование BULK COLLECT INTO для коллекции какого-либо типа может значительно ускорить SQL в операторах PL / SQL.

    0
    ответ дан 8 December 2019 в 14:44
    поделиться

    DML (например, SELECT, UPDATE, DELETE), выданный через SQLPlus, выдается непосредственно в механизм SQL Oracle, тогда как DML в процедуре PLSQL является сначала обрабатывается PL / SQL (например, для привязки переменных), а затем отправляется в механизм SQL.

    По большей части один и тот же оператор в PL / SQL будет работать так же, как SQL, и оба способа обычно производят один и тот же план выполнения. По моему опыту (обычно, когда требуется привязка переменных), это может привести к очень разной производительности. Я встречал случаи, когда SELECT, выдаваемый в SQL Plus, занимал доли секунды, в то время как SELECT, выданный через PL / SQL, занимал 1-2 минуты.

    Я рекомендую вам настроить свой оператор так, чтобы он работал так же хорошо в PL / SQL как и в SQL. Сосредоточьтесь на правильном связывании переменных (используя FORALL и BULK COLLECT), но также изучите планы выполнения и выполните модульные тесты.

    Я встречал случаи, когда SELECT, выдаваемый в SQL Plus, занимал доли секунды, в то время как SELECT, выданный через PL / SQL, занимал 1-2 минуты.

    Я рекомендую вам настроить свой оператор так, чтобы он работал так же хорошо в PL / SQL как и в SQL. Сосредоточьтесь на правильном связывании переменных (используя FORALL и BULK COLLECT), но также изучите планы выполнения и выполните модульные тесты.

    Я встречал случаи, когда SELECT, выдаваемый в SQL Plus, занимал доли секунды, в то время как SELECT, выданный через PL / SQL, занимал 1-2 минуты.

    Я рекомендую вам настроить свой оператор так, чтобы он работал так же хорошо в PL / SQL как в SQL. Сосредоточьтесь на правильном связывании переменных (используя FORALL и BULK COLLECT), но также изучите планы выполнения и выполните модульные тесты.

    0
    ответ дан 8 December 2019 в 14:44
    поделиться

    Вы действительно сравниваете здесь примерно одинаковые? Выполняете ли вы необработанные операторы SQL в PL / SQL (оптимальный случай) или используете явные или неявные курсоры для возврата значений, а затем их обработки? Есть большая разница.

    1
    ответ дан 8 December 2019 в 14:44
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: