Как мне оптимизировать запрос Oracle? - PullRequest
3 голосов
/ 11 января 2012

Мне дали запрос SQL, заявив, что я должен оптимизировать этот запрос.

Я наткнулся explain plan.Итак, в SQL-разработчике я запустил план объяснения для

. Он разделил запрос на несколько частей и показал стоимость каждой из них.

Как мне оптимизировать запрос?Что я ищу?Элементы с высокими затратами?

Я немного новичок в БД, поэтому, если вам нужна дополнительная информация, пожалуйста, спросите меня, и я постараюсь ее получить.

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

Запрос:

SELECT cr.client_app_id,
  cr.personal_flg,
  r.requestor_type_id 
FROM credit_request cr,
  requestor r,
  evaluator e 
WHERE cr.evaluator_id = 96 AND
  cr.request_id = r.request_id AND
  cr.evaluator_id = e.evaluator_id AND
  cr.request_id != 143462 AND
  ((r.soc_sec_num_txt = 'xxxxxxxxx' AND         
  r.soc_sec_num_txt IS NOT NULL) OR
  (lower(r.first_name_txt) = 'test' AND
  lower(r.last_name_txt) = 'newprogram' AND
  to_char(r.birth_dt, 'MM/DD/YYYY') = '01/02/1960' AND
  r.last_name_txt IS NOT NULL AND
  r.first_name_txt IS NOT NULL AND
  r.birth_dt IS NOT NULL))

При выполнении плана объяснения я пытаюсь загрузить снимок экрана.

OPERATION    OBJECT_NAME     OPTIONS     COST 
 SELECT STATEMENT                        15 
 NESTED LOOPS              
 NESTED LOOPS                            15 
 HASH JOIN                               12 
 Access Predicates 
 CR.EVALUATOR_ID=E.EVALUATOR_ID 
 INDEX  EVALUATOR_PK     UNIQUE SCAN     0 
 Access Predicates 
 E.EVALUATOR_ID=96 
 TABLE ACCESS  CREDIT_REQUEST    BY INDEX ROWID      11 
 INDEX  CRDRQ_DONE_EVAL_TASK_REQ_NDX     SKIP SCAN   10 
 Access Predicates 
 CR.EVALUATOR_ID=96 
 Filter Predicates 
 AND 
 CR.EVALUATOR_ID=96 
 CR.REQUEST_ID<>143462 
 INDEX  REQUESTOR_PK     RANGE SCAN      1 
 Access Predicates 
 CR.REQUEST_ID=R.REQUEST_ID 
 Filter Predicates 
 R.REQUEST_ID<>143462 
 TABLE ACCESS  REQUESTOR     BY INDEX ROWID      3 
 Filter Predicates 
 OR 
 R.SOC_SEC_NUM_TXT='XXXXXXXX' 
 AND 
 R.BIRTH_DT IS NOT NULL 
 R.LAST_NAME_TXT IS NOT NULL 
 R.FIRST_NAME_TXT IS NOT NULL 
 LOWER(R.FIRST_NAME_TXT)='test' 
 LOWER(R.LAST_NAME_TXT)='newprogram' 
 TO_CHAR(INTERNAL_FUNCTION(R.BIRTH_DT),'MM/DD/YYYY')='01/02/1960' 

Ответы [ 2 ]

3 голосов
/ 11 января 2012

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

SELECT
    cr.client_app_id,
    cr.personal_flg,
    r.requestor_type_id 
FROM 
    credit_request cr
    inner join requestor r on
        cr.request_id = r.request_id
    inner join evaluator e on
        cr.evaluator_id = e.evaluator_id
WHERE 
    cr.evaluator_id = 96
    and cr.request_id != 143462
    and (r.soc_sec_num_txt = 'xxxxxxxxx' 
        or (
            lower(r.first_name_txt) = 'test'
            and lower(r.last_name_txt) = 'newprogram'
            and r.birth_dt = date '1960-01-02'
        )
    )

Во-первых, соединение через запятую создает перекрестное соединение, которого вы хотите избежать. К счастью, Oracle достаточно умен, чтобы делать это как внутреннее соединение, так как вы указали условия соединения, но вы хотите быть явным, чтобы случайно не пропустить что-то.

Во-вторых, ваши is not null проверки бессмысленны - если столбец равен null, а проверка =, которую вы делаете, вернет false для этой строки. Фактически, любое сравнение со столбцом null, даже null = null, возвращает false. Вы можете попробовать это с select 1 where null = null и select 1 where null is null. Только второй возвращается.

В-третьих, Oracle достаточно умен, чтобы сравнивать даты с форматом ISO (по крайней мере, в последний раз, когда я его использовал, так и было). Вы можете просто сделать r.birth_dt = date '1960-01-02' и избегать строкового формата в этом столбце.

При этом ваш запрос не совсем плохо написан с точки зрения вопиющих ошибок производительности. То, что вы хотите посмотреть, это индексы. У evaluator есть один на evaluator_id? credit_request? Какие они типы? Как правило, у evaluator будет один на PK evaluator_id, а у credit_request будет также один для этого столбца. То же самое для requestor и request_id столбцов.

Другими индексами, которые вы можете рассмотреть, являются все поля, которые вы используете для фильтрации. В этом случае soc_sec_num_txt, first_name_txt, last_name_txt, birth_dt. Попробуйте добавить индекс из нескольких столбцов для последних трех, а индекс для одного столбца - в столбец soc_sec_num_txt.

2 голосов
/ 12 января 2012

После рефакторинга запроса появляются индексы, поэтому из сообщения @ eric следует:

credit_request:
Вы присоединяетесь к этому requestor на request_id, который я надеюсь, является уникальным.В предложении where у вас есть условие для evaluator_id и выберите client_app_id и personal_flg в запросе.Таким образом, вам, вероятно, нужен уникальный индекс для credit_request из (request_id, evaulator_id, client_app_id, personal_flg.

Помещая выбранные столбцы в индекс, вы избегаете by index rowid, что означает, что вы выбрали свои значения из индекса, а затем снова вошли в таблицу, чтобы получить дополнительную информацию.Если эта информация уже есть в индексе, то в этом нет необходимости.

Вы присоединяете ее к evaluator на evaluator_id, который включен в первый индекс.

requestor:
Это присоединяется к request_id, и ваше предложение where включает soc_sec_num_text, lower(first_name_txt), lower(last_name_txt) и birth_dt.Итак, вам нужен уникальный, если возможно, индекс для (request_id, soc_sec_num_text), потому что или это еще более сложно, потому что у вас действительно должен быть индекс для максимально возможного числа условий.Вы также выбираете requestor_type_iud.

В этом случае, чтобы избежать функционального индекса со многими столбцами, я бы индексировал (request_id, soc_sec_num_text, birth_dt ), если у вас есть пространство, время и наклон, то добавление lower(first_name_txt)... etc к этому может улучшить скорость в зависимости от того, какСелективный столбец есть.Это означает, что, если, например, значений намного больше, first_name_txt, чем birth_dt, лучше поставить это значение перед индексом birth_dt в индексе, чтобы ваш запрос меньше сканировал, если он не уникаленindex.

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

evaluator:
Присоединяется только к evaluator_id, поэтому вам нужен уникальный, если возможно, индекс для этого столбца.

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