Различия в производительности при использовании параметров или констант в PL / SQL - PullRequest
0 голосов
/ 20 сентября 2018

У меня проблема с производительностью.

Первый PL / SQL (большая часть времени никогда не заканчивается и процесс базы данных ОС всегда превышает 90%):

DECLARE 
  myId nvarchar2(10) := '0;WF21izb0';
BEGIN
  insert into MY_TABLE (select * from MY_VIEW where ID = myId);
END;

Второй PL / SQL (заканчивается успешным результатом через 50 с):

BEGIN
  insert into MY_TABLE (select * from MY_VIEW where ID = '0;WF21izb0');
END;

select count(*) from MY_VIEW 

также не является завершающим вызовом, за этим представлением существует множество объединений таблиц.

select count(*) from MY_VIEW where ID = '0;WF21izb0'

заканчивается через 50 с количеством = 60000.

Может кто-нибудь объяснить мне причину, по которой мой первый PL / SQL не заканчивается после 50-х годов?В чем разница между использованием статической строки и объявленного параметра?

Ответы [ 2 ]

0 голосов
/ 21 сентября 2018

Я проверял некоторые следы, но после прочтения комментария APC и ответа Илариона я оказался в этом решении:

declare sql_stmt VARCHAR2(200); id VARCHAR2(10) := '0;WF21izb0'; BEGIN sql_stmt := 'insert into MY_TABLE (select * from MY_VIEW where ID = :1)'; EXECUTE IMMEDIATE sql_stmt using id; END;

Это сделано в 50-х годах, иid теперь может быть параметром функции / процедуры.Спасибо за комментарии.

0 голосов
/ 20 сентября 2018

Это сводится к тому, что подсистема БД знает о ваших данных и вашем запросе при подготовке плана выполнения запроса.

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

Когда вы используете переменную PL / SQLфактический запрос, для которого определен план, отличается.Это что-то вроде:

insert into MY_TABLE (select * from MY_VIEW where ID = :param)

Как видите, механизм БД теперь не имеет информации о значении, которое будет использоваться при выполнении запроса.Таким образом, лучший план для такого сценария - подготовить что-то, что в среднем хорошо для большинства вероятных значений (т. Е. Посмотрите, какие значения в БД будут соответствовать этому месту чаще всего, т. Е. Значения, которые преобладают).

Если ваши данные несбалансированы, а значение '0;WF21izb0' редко (или вообще отсутствует) в ваших данных, можно использовать селективный индекс для сужения того, что необходимо обрабатывать, относительно скоро в критических частяхплан выполнения.Однако этот план будет иметь неприятные последствия, когда вы будете использовать значение, которое повсеместно - использование индекса будет контрпродуктивным.Лучшим планом для такого случая может быть полное сканирование таблицы.Возможно, тот же самый, который используется при выполнении select count(*) from MY_VIEW.

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

Редактировать :
В общем, следуйте советам из комментариев к вопросу и изучите свои планы выполнения и данные профиля выполнения.Вы должны быть в состоянии найти виновника.Оттуда может быть не очевидно, каково решение, но тем не менее, вы знаете свои данные и отношения намного лучше, чем мы.

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