Повышение производительности запросов oracle без индексации

StackOverflow https://stackoverflow.com/questions/244087

  •  04-07-2019
  •  | 
  •  

Вопрос

Что я могу сделать, чтобы повысить производительность запроса Oracle query без создания индексов?

Вот запрос, который я пытаюсь выполнить быстрее:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
AND a.ItemNum = b.ItemNum
AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

Ни один из этих столбцов не проиндексирован, и каждая из таблиц содержит миллионы записей.Излишне говорить, что выполнение запроса занимает более 3 с половиной минут.Это сторонняя база данных в производственной среде, и мне не разрешено создавать какие-либо индексы, поэтому любые улучшения производительности должны быть внесены в сам запрос.

Спасибо!

Это было полезно?

Решение

Сначала я бы переписал запрос в соответствии со стандартом ANSI:

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a
INNER JOIN itempages b ON b.ItemNum = a.ItemNum
INNER JOIN keygroupdata c ON c.ItemNum = b.ItemNum
WHERE a.ItemType IN (112,115,189,241)
ORDER BY a.DateStored DESC

Это облегчает чтение и понимание того, что происходит.Это также поможет вам не совершать ошибок (т.е.Перекрестное соединение), что может вызвать действительно большие проблемы.Затем я бы получил план Explain, чтобы посмотреть, что СУБД делает с этим запросом.Пытается ли он использовать какие-то индексы?Правильно ли он соединяет таблицы?

Затем я бы просмотрел таблицы, с которыми я работаю, чтобы увидеть, есть ли уже существующие индексы, которые я мог бы использовать для ускорения моего запроса.Наконец, как и все остальные, я бы удалил предложение Order By и просто сделал это в коде.

Другие советы

Попросите третью сторону проиндексировать свои столбцы join, как они должны были сделать в первую очередь!Без индексов Oracle не на что опереться, кроме грубой силы.

Возможно, вы захотите попробовать создать материализованное представление в любой из этих таблиц.Затем вы можете создать индекс в материализованном представлении, который поможет ускорить выполнение запроса (который затем будет запрашивать материализованное представление вместо необработанной таблицы).

Конечно, если ваша базовая таблица обновлена, ваше представление и индексы необходимо будет обновить.

Во-первых, посмотрите на план выполнения.Точно ли это отражает количество строк, которые должны быть извлечены на каждом этапе выполнения запроса?Насколько избирательным является предикат "a.ItemType В (112,115,189,241)"?Показывает ли план выполнения какое-либо использование временного дискового пространства для объединений или сортировок?

На самом деле, возможно, вы можете изменить вопрос, включив в него план выполнения.

Также убедитесь, что у вас не отключены хэш-соединения, что иногда имеет место в системах, настроенных на OLTP, поскольку они являются наиболее эффективным способом равносоединения объемных данных в Oracle.Они должны быть указаны в плане выполнения.

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

Если вы работаете на Oracle до 9i, это иногда дает неожиданные преимущества.

select 
  c.claimnumber,
  a.itemdate, 
  c.dtn,
  b.filepath
from 
  (
  select itemdate
  from items it
  where it.itemtype in(112,115,189,241)
  ) a
  itempages b,
  keygroupdata c
where a.itemnum = b.itemnum
  and b.itemnum = c.itemnum

Вы также можете попробовать добавить подсказки /+ПРАВИЛО/ или /+ЗАКАЗАННЫЙ/ чтобы посмотреть, что произойдет...опять же, особенно в старых версиях, это иногда давало неожиданные результаты.

SELECT /*+RULE*/
  c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM
  items a,
  itempages b,
  keygroupdata c
WHERE a.ItemType IN (112,115,189,241)
  AND a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY a.DateStored DESC

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

Затем вы можете сделать дорогостоящий запрос "автономным" и получить более быстрые / качественные результаты для интерактивного запроса.

Это тот запрос, который вы часто выполняете?Похоже, что в интересах владельца базы данных было бы создать индексы, необходимые для ускорения этого запроса.3,5 минуты, которые вы тратите на выполнение запроса, должны оказать некоторое влияние на их производственную среду!

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

Кстати, что тебе разрешено делать?Просто читать?Если вы можете создавать временные таблицы и помещать в них индексы, я мог бы рассмотреть возможность создания временных копий таблицы, их индексирования, а затем выполнить объединение с помощью индекса с временными копиями.

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

with a as (
  select 
    * 
  from 
    items 
  where 
    ItemType IN (112,115,189,241)
)
SELECT 
  c.ClaimNumber
  , a.ItemDate
  , c.DTN, b.FilePath
FROM 
  a,
  itempages b,
  keygroupdata c
WHERE 
  a.ItemNum = b.ItemNum
  AND b.ItemNum = c.ItemNum
ORDER BY 
  a.DateStored DESC

Вы также можете попробовать /*+ MATERIALIZE */ подсказка в WITH оговорка.

На самом деле я нахожу, что старый синтаксис соединения oracle намного легче читать, чем ansi sql ^^

Без индексации этот запрос будет только ухудшаться по мере увеличения размера таблицы.С учетом сказанного попробуйте удалить предложение order by и выполнить такую сортировку на стороне клиента.

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

Например, у вас есть A.ItemNum = B.ItemNum И B.ItemNum = C.ItemNum.Попробуйте также добавить A.ItemNum = C.ItemNum.Однако я почти уверен, что оптимизатор достаточно умен, чтобы разобраться в этом самостоятельно - хотя попробовать стоит.

В зависимости от типа данных столбца ItemType вы можете ускорить выполнение, используя следующее: если это varchar, Oracle выполнит неявные преобразования.

SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath
FROM items a,
itempages b,
keygroupdata c
WHERE ((a.ItemType IN ('112','115','189','241'))
AND (a.ItemNum = b.ItemNum)
AND (b.ItemNum = c.ItemNum))
ORDER BY a.DateStored DESC

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

Помимо этого, взгляните на план выполнения.Вы можете увидеть, что он соединяет таблицы в неоптимальном порядке (напримерэто может быть соединение b и c перед соединением с a, которое имеет условие фильтрации).

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

Обновить:Ответ на комментарий привел меня к это презентация, которая могла бы быть полезной или, по крайней мере, интересной.

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

В этом случае использование подсказки, такой как /*+ ORDERED */, вполне может быть единственным вариантом, позволяющим оптимизатору надежно выбрать хороший путь выполнения.Возможно, также стоит добавить внешние ключи и первичные ключи, но определить их как ОТКЛЮЧАЕМЫЕ и ПРОВЕРЯЕМЫЕ.

Я предполагаю, что полезность этого комментария зависит от того, насколько далеко заходит неприятие индексов в YMMV.

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

Ну, поскольку вы не можете создавать индексы, я бы убедился, что вся статистика актуальна, тогда я бы переписал запрос таким образом:

with a as (select /*+ MATERIALIZE */ ItemType, ItemNum, DateStored, ItemDate from items where ItemType in (112,115,189,241)) SELECT c.ClaimNumber, a.ItemDate, c.DTN, b.FilePath FROM a, itempages b, keygroupdata c WHERE a.ItemNum = b.ItemNum AND b.ItemNum = c.ItemNum ORDER BY a.DateStored DESC

Удалите ЗАКАЗ С ПОМОЩЬЮ

выполните сортировку после того, как вы вернете строки обратно в свое приложение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top