Oracle - пустое или пустое значение параметра в функции

Я пытаюсь получить результат от функции, которая делает запрос, обрабатывает поля и возвращает коллекцию.

Если я возьму запрос функции и выполню отдельно, она вернется примерно через 10 минут, в зависимости от параметров, которые я поставил. Если я передам функции те же параметры, она продолжит обработку, и через 45 минут я не получу никакого результата.

После запроса у меня есть только несколько if, которые проверяют нулевые значения или значения, которые выше, чем другие.

Я думаю, проблема в том, что я передаю некоторые параметры нулевыми или пустыми, и это приводит к сбою запроса. Вот моя проблема:

У меня есть тип:

CREATE OR REPLACE TYPE TypeForFunction is OBJECT (
    -- all my fields here
 )
/

Затем сделайте коллекцию:

CREATE OR REPLACE TYPE TypeForFunctionTable AS
    TABLE OF TypeForFunction
/

Тогда моя функция выглядит так:

CREATE OR REPLACE FUNCTION MyFunction
(
  /* here I have five parameters and in the case that the query crashes, 
     two of them I'm trying to pass blank or null */

  COL in varchar2, -- This I pass a valid value
  INDEX in number, -- same here
  REF in varchar2, -- This one I'm trying to pass Blank ('') or Null and i 
                      get no result no matter which one I pass.
  P in varchar2,   
  BLOQ in varchar2 -- Same null or blank here

) RETURN TypeForFunctionTable
IS  
  result_table TypeForFunctionTable;
  i integer := 0;
begin 
     select      
            TypeForFunction(

                /* Here I have some subquerys that I use the parameters null which 
                   I use the same way as parameter REF. Like: */ 
                
                and (MyTable.FieldP = P or P is null)
                and (MyTable.FielBloq = BLOQ or BLOQ is null)

            ) BULK COLLECT into result_table   
     from              
        myTables
        
     where
        -- here I have a clause like

        (MyTable.FieldREF = REF or REF is null)
     ;  
     For i in 1..result_table.count loop                 
         /* Here I have some if's, but nothing to crash the query like it happens. 
            Things like: */

         if MyVar > 0 then
            COL = REF;
            INDEX = INDEX + 100;


              
     end loop;        
     return result_table;     
 
end MyFunction;
/

Чтобы вызвать функцию, которую я пытаюсь:

select * from table(MyFunction('59', 1, '', 'IV18', ''));

Также попробуйте:

select * from table(MyFunction('59', 1, Null, 'IV18', Null));

В любом случае я получаю тот же результат, функция не возвращается и не выдает никаких ошибок через 45 минут.

Есть ли лучший способ работать с параметрами, которые я могу передавать или не передавать?


person Pablo F. Wachsmann    schedule 18.06.2018    source источник
comment
Сколько записей возвращает эта функция? Функция использует BULK COLLECT и помещает все записи в коллекцию, которая создается в памяти. Если записей много, то ему может не хватить памяти, и он подкачивает таблицу памяти на диске - это всегда медленно. Я не уверен, что эта функция должна делать, почему вы хотите выбирать из функции, а не напрямую из таблицы, используя простой SELECT, это должно быть медленным.   -  person krokodilko    schedule 19.06.2018
comment
Я не понимаю, какое отношение имеет проблема null против '' к вопросу. Нет никакой разницы для varchar2 параметров, которые есть у вашей функции. В чем именно вопрос?   -  person William Robertson    schedule 19.06.2018
comment
Запрос возвращает набор из 7 тыс. записей, более или менее. Я делаю это, потому что мне нужно обработать столбцы, которые он возвращает, и я подумал, что это лучший способ. Также подумал, что это нулевой параметр, потому что, если запустить все допустимые значения, он работает отлично. Firebird может обработать такой объем данных, я не могу поверить, что оракул не может обработать.   -  person Pablo F. Wachsmann    schedule 19.06.2018
comment
Конечно, Oracle может обрабатывать огромные объемы данных. Однако легко написать плохо работающий запрос, особенно если вы новичок в Oracle. Вы просите нас дать советы по оптимизации, не показывая деталей своей реализации. Так что дельного совета дать не можем. Мы можем сказать, что почти наверняка низкая производительность связана с тем, как вы написали свой код. Если вы хотите опубликовать актуальную программу, запрос и структуры данных, возможно, мы сможем быть более полезными.   -  person APC    schedule 19.06.2018
comment
Я задал вопрос о переменных из-за различного поведения, когда я передаю или не получаю значения. Но если использование массовой коллекции в сочетании с медленным запросом может вызвать проблему, я могу попытаться оптимизировать ее.   -  person Pablo F. Wachsmann    schedule 19.06.2018


Ответы (1)


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

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

Я начал искать и нашел этот ответ:

Хранимая процедура зависает без объяснения причин

Это ответ SQL Server, но затем я начал искать, затрагивает ли проблема также Oracle, и наткнулся на этот пост:

https://dba.stackexchange.com/questions/198443/does-oracle-database-suffer-from-parameter-sniffing-issue

Итак, я объявил локальные переменные как в своей функции, так и в процедуре, и эти переменные получили параметры.

Теперь моя функция выглядит так:

CREATE OR REPLACE FUNCTION MyFunction
(
  /* here i have five parameters and in the case that the query crashes, 
     two of them i'm trying to pass blank or null */

  COL in varchar2, -- This I pass a valid value
  INDEX in number, -- same here
  REF in varchar2, -- This one I'm trying to pass Blank ('') or Null and i 
                      get no result no matter wich one I pass.
  P in varchar2,   
  BLOQ in varchar2 -- Same null or blank here

) RETURN TypeForFunctionTable
IS  
  result_table TypeForFunctionTable;
  i integer := 0;
  LOCAL_COL varchar2(4) := COL;
  LOCAL_REF varchar2(15) := REF;
  LOCAL_P varchar2(6) := P;
  LOCAL_BLOQ varchar2(1) :=;

И я использовал переменные «LOCAL» во всех запросах, и все работало нормально. Решил проблему. Я не мог поблагодарить парня, который прокомментировал оригинальный пост, из-за моей репутации, но я очень благодарен.

Также благодарен за ответы!

person Pablo F. Wachsmann    schedule 20.06.2018