производительность oracle sql в большом наборе данных

У меня такой запрос.

Я использую Jpa и получаю только первые 50 результатов, но для моей таблицы с 2 миллионами записей это занимает слишком много времени.

Как увеличить производительность?

SELECT * FROM TRANSACTION 
WHERE
   (trunc(REQUEST_TIME,'MI') between to_date('1390/01/01 01:01','YYYY/MM/DD HH24:MI','nls_calendar=persian') 
                                 and to_date('1396/11/01 01:01','YYYY/MM/DD HH24:MI','nls_calendar=persian'))
and  CUSTOMER like '%123%'
and  (case when (ERROR_CODE is not null and ERROR_CODE <> 200) then -1 
           when (ERROR_CODE is not null and ERROR_CODE =200) then 200 
       else 0 end =0)
and (URL = 'url1')
and ( SOURCE like '%123%')
and ( ERROR_CODE=200) 
and ( REQUEST_ID like '%1234%')

person Community    schedule 19.08.2017    source источник
comment
Ваши условия по ERROR_CODE противоречивы. В частности, выражение CASE никогда не должно совпадать, если только ERROR_CODE не равно NULL. Но затем это отфильтровывается более поздним условием.   -  person Gordon Linoff    schedule 19.08.2017
comment
какие индексы у вас есть на столе?   -  person Jens Schauder    schedule 21.08.2017


Ответы (2)


Удалите отсюда функцию TRUNC, она не нужна, но не позволяет СУБД использовать индекс в столбце REQUEST_TIME (если он есть):

   (trunc(REQUEST_TIME,'MI') between .......

Удалите отсюда условие ERROR_CODE is not null, если ERROR_CODE <> 200 или ERROR_CODE =200, то оно всегда должно быть NOT NULL:

case when (ERROR_CODE is not null  and ERROR_CODE <> 200)
then -1 when (ERROR_CODE is not null and ERROR_CODE =200)
then 200 else 0 end =0)

Если вы упростите приведенное выше условие, вы получите:

case when ERROR_CODE <> 200 then -1 
     when ERROR_CODE =200 then 200 
     else 0 
end =0

Если вы изучите приведенное выше упрощенное условие, станет очевидным, что оно проверяет только часть «else 0», поэтому его можно упростить до следующего:

ERROR_CODE IS NULL

но поскольку в вашем запросе есть еще одно условие and ( ERROR_CODE=200), первое условие исключает другое условие and ( ERROR_CODE=200), поэтому я думаю, что вы не показываете нам реальный запрос в вопросе. Я бы просто удалил это условие, потому что это, скорее всего, логическая ошибка.


После приведенных выше упрощений вы получите:

SELECT * FROM TRANSACTION 
WHERE
  REQUEST_TIME between to_date('1390/01/01 01:01','YYYY/MM/DD HH24:MI','nls_calendar=persian') 
                   and to_date('1396/11/01 01:01','YYYY/MM/DD HH24:MI','nls_calendar=persian')
  and  CUSTOMER like '%123%'
  and (URL = 'url1')
  and ( SOURCE like '%123%')
  and ( ERROR_CODE=200) and( REQUEST_ID like '%1234%')

Теперь убедитесь, что на REQUEST_TIME создан индекс, если нет, то создайте его и проверьте работоспособность запроса.

person krokodilko    schedule 19.08.2017

При условии, что это не специальный (редко используемый) тип запроса.
Определите функциональный индекс для trunc(REQUEST_TIME,'MI') в качестве столбца.

person Barbaros Özhan    schedule 19.08.2017