Скорость выгружаемых запросов в Oracle

это бесконечная тема для меня, и мне интересно, могу ли я что-то упустить. По сути, я использую два типа операторов SQL в приложении:

  1. регулярные запросы с" резервным " ограничением
  2. сортированные и выгружаемые запросы

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

корпус 1 очень просто. Мы просто добавляем дополнительный ROWNUM фильтр:

WHERE ...
  AND ROWNUM < ?

это довольно быстро, так как CBO Oracle примет этот фильтр во внимание для своего плана выполнения и, вероятно, применит FIRST_ROWS операция (аналогичная той, которая применяется /*+FIRST_ROWS*/ намек.

корпус 2, однако немного сложнее с Oracle, так как нет LIMIT ... OFFSET статья как и в других РСУБД. Поэтому мы помещаем наш" деловой " запрос в техническую оболочку как таковую:

SELECT outer.* FROM (
  SELECT * FROM (
    SELECT inner.*, ROWNUM as RNUM, MAX(ROWNUM) OVER(PARTITION BY 1) as TOTAL_ROWS
    FROM (
      [... USER SORTED business query ...]
    ) inner
  ) 
  WHERE ROWNUM < ?
) outer
WHERE outer.RNUM > ?

отметим, что TOTAL_ROWS поле вычисляется, чтобы знать, сколько страниц у нас будет даже без извлечения всех данных. Теперь этот запрос подкачки обычно вполне удовлетворителен. Но время от времени (как я уже сказал, при запросе записей 5M+, возможно, включая неиндексированные поиски), это работает для 2-3minutes.

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

мне интересно, это современное моделирование LIMIT ... OFFSET, включая TOTAL_ROWS в Oracle, или есть лучше решение, которое будет быстрее по дизайну, например, с помощью ROW_NUMBER() функция окна вместо ROWNUM псевдо-колонну?

4 ответов


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

  1. попробуйте убедиться, что никакие функции не вызываются во внутреннем SQL-эти может быть вызвано 5 миллионов раз, чтобы вернуть первые 20 строк. Если вы можете переместить эти вызовы функций во внешний запрос, они будут называться меньше.
  2. используйте подсказку FIRST_ROWS_n, чтобы подтолкнуть Oracle к оптимизации для того, что вы никогда не вернете все данные.

изменить:

другая мысль: в настоящее время вы представляете пользователю отчет, который мог бы возвращаться тысячи или миллионы строк, но пользователь никогда не реалистично просматривая их все. Вы не можете заставить их выбрать меньший объем данных, например, ограничив диапазон дат, выбранный до 3 месяцев (или что-то еще)?


возможно, вы захотите проследить запрос, который занимает много времени, и посмотреть его план объяснения. Скорее всего, узкое место производительности происходит из расчета TOTAL_ROWS. Oracle должен считывать все данные, даже если вы получаете только одну строку, это общая проблема, с которой сталкиваются все СУБД с этим типом запроса. Никакая реализация TOTAL_ROWS не обойдет это.

радикальный способ ускорить этот тип запроса-отказаться от вычисления TOTAL_ROWS. Просто покажите, что есть дополнительная страница. Ваши пользователи действительно должны знать, что они могут просматривать страницы 52486? Оценка может быть достаточной. Вот еще одно решение, реализованное на поиск Google, например, оценить количество страниц, вместо того, чтобы подсчитывать их.

разработка точного и эффективного алгоритма оценки может быть нетривиальной.


A "ПРЕДЕЛ ... OFFSET " - это в значительной степени синтаксический сахар. Это может сделать запрос более красивым, но если вам все равно нужно прочитать весь набор данных и отсортировать его и получить строки "50-60", то это работа, которую нужно сделать.

Если у вас есть индекс в правильном порядке, то это может помочь.


может быть лучше выполнить два запроса вместо попытки count () и вернуть результаты в том же запросе. Oracle может ответить на count () без сортировки или присоединения ко всем таблицам (исключение таблицы join на основе объявленных ограничений внешнего ключа). Это то, что мы обычно делаем в нашем приложении. Для инструкций performance important мы пишем отдельный запрос, который, как мы знаем, вернет правильное количество, поскольку иногда мы можем сделать лучше, чем Оракул.

кроме того, вы можете сделать выбор между производительностью и актуальность данных. Возвращение первых 5 страниц будет почти так же быстро, как возвращение первой страницы. Таким образом, вы можете рассмотреть возможность хранения результатов с 5 страниц во временной таблице вместе с датой истечения срока действия информации. Возьмите результат из временной таблицы, если он действителен. Поместите фоновую задачу, чтобы периодически удалять истекшие данные.