Улучшение производительности оракулов без индексации - PullRequest
7 голосов
/ 28 октября 2008

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

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

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 с половиной минут. Это сторонняя база данных в производственной среде, и мне не разрешается создавать какие-либо индексы, поэтому в самом запросе необходимо будет повысить производительность.

Спасибо!

Ответы [ 16 ]

8 голосов
/ 28 октября 2008

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

7 голосов
/ 28 октября 2008

Сначала я бы переписал запрос, чтобы он соответствовал стандарту 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

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

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

6 голосов
/ 28 октября 2008

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

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

3 голосов
/ 28 октября 2008

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

Если вы работаете в 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

Вы также можете попробовать добавить подсказки / + RULE / или / + ORDERED /, чтобы увидеть, что происходит ... опять же, особенно со старыми версиями, иногда это может удивлять результаты.

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
3 голосов
/ 28 октября 2008

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

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

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

1 голос
/ 10 ноября 2011

Я знаю, что эта ветка очень старая, но для поисковых систем я все же хотел предложить альтернативное решение, которое будет работать на 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.

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

1 голос
/ 28 октября 2008

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

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

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

1 голос
/ 28 октября 2008

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

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

0 голосов
/ 16 ноября 2017

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

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

0 голосов
/ 13 октября 2011

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

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