Настройка Oracle для запроса с помощью query annidate

#oracle #performance #database-performance

#Oracle #Производительность #база данных-производительность

Вопрос:

я пытаюсь улучшить запрос. У меня открыт набор данных для запроса. Каждый билет имеет разные строки, каждая строка представляет собой обновление билета. Существует поле (dt_update), которое отличается в каждой строке.

У меня есть эти индексы в st_remedy_full_light.
IDX_ASSIGNMENT (ПРИСВОЕНИЕ)
IDX_REMEDY_INC_ID (REMEDY_INC_ID)
IDX_REMDULL_LIGHT_DTUPD (DT_UPDATE)

Теперь запрос выполняется за 8 секунд. Для меня высока.

 WITH last_ticket AS
  ( SELECT *
   FROM st_remedy_full_light a
   WHERE a.dt_update IN
     ( SELECT MAX(dt_update)
       FROM st_remedy_full_light
       WHERE remedy_inc_id = a.remedy_inc_id
     )
  )
SELECT remedy_inc_id, ASSIGNMENT FROM last_ticket 
  

Это план
Объясните план
Как я мог бы улучшить этот запрос?

P.S. Это всего лишь часть большого запроса

Дополнительная информация: — Таблица st_remedy_full_light содержит 529,507 строк

Комментарии:

1. Может ли быть несколько ‘st_remedy_full_light’ с одинаковым ‘dt_update’ для ‘remedy_inc_id’?

2. индекс (remedy_inc_id, dt_update) — или, возможно, даже (remedy_inc_id, dt_update, назначение) — должен помочь вам, если вы не хотите / не можете изменить подзапрос на то, что предлагает Тони Эндрюс. Т. Е. один индекс, содержащий несколько столбцов, а не индекс для каждого столбца — Oracle сможет использовать только один из этих индексов с одним столбцом для запроса, он не может использовать все три, даже если вы используете все три столбца в своем запросе . Такой индекс, вероятно, также помог бы предлагаемому запросу Тони Эндрю.

3. @EvgeniyK. не только у remedy_inc_id есть больше dt_update, но не у другого.

4. @Boneist Я не думал использовать несколько индексов. Поработайте над этим немного лучше с помощью (remedy_inc_id, dt_update, назначение). Но странно, что он использует индекс только для получения полей в select, а не для условия where в подзапросе

Ответ №1:

Вы могли бы попробовать:

 WITH last_ticket AS
  ( SELECT remedy_inc_id, ASSIGNMENT,
           rank() over (partition by remedy_inc_id order by dt_update desc) rn
   FROM st_remedy_full_light a
  )
SELECT remedy_inc_id, ASSIGNMENT FROM last_ticket 
where rn = 1;
  

Комментарии:

1. Привет, Тони, спасибо за твой ответ… К сожалению, я использовал это решение, но, как ни странно, медленнее, чем мое решение.

2. Не могли бы вы поделиться более подробной информацией о том, почему этот запрос будет выполняться быстрее по сравнению с исходным.

3. @NzGuy Я бы ожидал , что он, вероятно , будет работать быстрее, потому что ему не нужно хэшировать соединение last_ticket с самим собой.

4. @vecio88 Как выглядит план при использовании этого запроса?

5. Поскольку в запросе нет предложения where и нет объединений, использование индекса не ожидается. Требуется полное сканирование. Если вы добавили индекс на (remedy_inc_id, ASSIGNMENT, dt_update) , то Oracle может полностью сканировать его вместо таблицы, что было бы быстрее, если индекс намного меньше таблицы.

Ответ №2:

Лучшим альтернативным запросом, который также намного проще выполнить, является следующий:

 select remedy_inc_id
     , max(assignment) keep (dense_rank last order by dt_update)
  from st_remedy_full_light
 group by remedy_inc_id
  

При этом будет использоваться только одно полное сканирование таблицы и группировка (хэш / сортировка) по, без самосоединений.

Не беспокойтесь об индексированном доступе, поскольку вы, вероятно, обнаружите, что полное сканирование таблицы здесь наиболее уместно. Если таблица не является действительно широкой и составной индекс по всем используемым столбцам (remedy_inc_id, dt_update, назначение) будет значительно быстрее для чтения, чем таблица.