2017-02-03 2 views
1

У меня есть хранимая процедура, которая принимает необязательные параметры из структуры Json. Если указаны значения json, параметры будут использоваться в качестве условий для курсоров. Если значение json не предусмотрено, я не хочу этого условия. Я решил это, используя Coalesce/Nvl в состоянии sql. Проблема в том, что процедура выполняется очень долго, используя Nvl/Coalesce. Можно ли использовать другой метод, который более эффективен? Возможно, динамический sql?Необязательный параметр, в котором условие - Как увеличить производительность - PL/SQL

Моя процедура:

Create or Replace Procedure findaccounts 


(jsonIn IN clob, 
jsonOut OUT varchar2) 
As 

obj json := json(jsonIn); 
json_obj_out json; 
json_lst json_list := json_list(); 

--Getstring is a function that sets variable to null if json value is not found 
istatus varchar2(10) := GetString(obj json, 'status'); 
icreatedate := GetString(obj json, 'daysold'); 
iage int := GetString(obj json, 'age'); 
irownum int := GetString(obj json, 'rownum'); 

Begin 
For rec in (Select A.accountnumber 
From Accounts A 
Inner Join Accountowner Ao On A.ownerId = Ao.Id 
Where A.Status = iStatus 
And A.daysold >= Coalesce(idaysold,A.daysold) 
And Ao.Age = Coalesce(iAge,Ao.Age) 
And rownum <= Coalesce(iRownum,5)) 

    loop 

     obj := json(); 

     obj.put('accountnumber',Rec.accountnumber); 
     json_lst.append(obj.to_json_value); 

    end loop; 

    json_lst.print; 
    jsonOut := json_lst.to_char(); 

End;  

постановило:

Performance бустер динамического SQL. Возможность иметь динамические переменные связывания была разрешена с помощью пакета dbms_sql, поскольку немедленный запуск этой опции не имеет.

ответ

2

Функционально Coalesce это отличный способ для обработки дополнительных критериев поиска. Производительность не очень хорошая. Оптимизатор не сможет эффективно оптимизировать работу, поскольку он решает план выполнения только один раз, оптимизируя критерии поиска при первом запуске SQL.

Если для получения приемлемой производительности потребуются разные планы выполнения, вам нужно использовать разные инструкции SQL для этих разных шаблонов поиска.

Вот два различных решения, которые я использовал в прошлом:

  1. создать несколько различных SQL: S, где каждый обрабатывает подмножество возможных критериев поиска, которые будут использовать один и тот же план выполнения. В вашем случае вы можете использовать его, если iAge - null, другое, когда idaysold - null, а третье - null.

  2. Использование динамического SQL.

+0

спасибо. Проблема разрешена через dbms_sql. Я не мог найти способ иметь необязательные переменные связывания через выполнение немедленно. – MrM

0

Вы можете исключить функцию COALESCE() так:

And (idaysold IS NULL OR A.daysold >= idaysold) 
And (iAge  IS NULL OR Ao.Age = iAge) 
And ((iRownum IS NULL AND ROWNUM <= 5) OR rownum <= iRownum) 
+0

И как это поможет с производительностью? –

+0

Использование функций в предложении 'WHERE' может означать, что вместо индекса столбца используется индекс на основе функций (или индекс). В этой версии нет функций, и следует использовать индексы столбцов (если они есть) - OP может запускать «EXPLAIN PLAN» в двух запросах и видеть, есть ли разница в используемых индексах. – MT0

+0

Я бы подумал, что оптимизатор Oracle будет просматривать 'coalesce' /' nvl' и расширять его, прежде чем передавать его оптимизатору. –

0

NVL обычно является наиболее эффективным методом фильтрации по необязательным параметрам. Он обычно будет работать лучше, чем COALESCE, OR, CASE, DECODE и другие подобные решения.

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

NVL обычно лучше всего работает, поскольку он, скорее всего, будет создавать CONCATENATION и FILTER операций. (Обратите внимание, что операция FILTERотличается от, чем раздел Filter в нижней части плана объяснения.) Эти операции позволяют Oracle создавать два разных плана выполнения и выбирать один во время выполнения в зависимости от переменных привязки.

В идеале план объяснить будет выглядеть примерно так:

---------------------------------------------------- 
| Id | Operation      | Name  | 
---------------------------------------------------- 
| 0 | SELECT STATEMENT    |   | 
| 1 | CONCATENATION    |   | 
| 2 | FILTER      |   | 
| 3 | TABLE ACCESS FULL   | MYTABLE | 
| 4 | FILTER      |   | 
| 5 | TABLE ACCESS BY INDEX ROWID| MYTABLE | 
| 6 |  INDEX UNIQUE SCAN   | MYTABLE_PK | 
---------------------------------------------------- 

Смотрите мой ответ here для тестового сценария, который демонстрирует, как NVL может работать.

Я думаю, что есть шанс, что ваш код имеет две неудачные проблемы. Без NVL он не будет генерировать отдельные планы выполнения. С NVL он может генерировать два плана, но, возможно, оба они плохие. Ff даже NVL не будет генерировать отдельные планы, тогда я предлагаю вам заглянуть в ответ Класа Линдбека.