Oracle Paging: аналитическая функция ROW_NUMBER () VS ROWNUM - PullRequest
2 голосов
/ 16 августа 2011

Когда пейджинг должен быть сделан на веб-сайте ... Какой метод работает лучше?

Аналитическая функция - ROW_NUMBER ()

ROWNUM

  • http://www.oracle.com/technetwork/issue-archive/2007/07-jan/o56asktom-086197.html
  • INMHO Я считаю этот подход более понятным для человека кодом

    SELECT * FROM (
      SELECT rownum rn, a.* 
      FROM(
        SELECT columnA, columnB
        FROM table 
        ORDER BY columnB
      ) a 
      WHERE rn <= OFFSET
    )
    WHERE rnum >= LOW_LIMIT
    
    • Примечание: я понимаю, что есть аналитические функции RANK и DENSE_RANK, но давайте предположим, что мне просто нужно пролистать детерминированные запросы.

    • Примечание 2: Дляполучить общее количество записей, о которых я думаю, используя отдельный простой счетчик запросов (*)

Ответы [ 3 ]

7 голосов
/ 16 августа 2011

Мне показался этот вопрос интересным, поэтому я попробовал несколько вещей.

У меня есть таблица с именем large_t, которая содержит около 1,1 млн строк.

Затем у меня есть два запроса:

select * 
from
(
  select rownum rnum, a.*
  from (
         select owner, object_name, object_id
         from large_t
         order by object_id
       ) a
  where rownum   <= 30      
) where rnum > 20;

И

select *
from
(
select owner, object_name, object_id,
       row_number() over (order by object_id) rnum
from large_t
) where rnum > 20 and rnum <= 30;

Если вы посмотрите на планы, сгенерированные двумя запросами, у первого есть операция:

SORT ORDER BY STOPKEY

В то время как аналитический запрос содержитОперация под названием

WINDOW SORT PUSHED RANK

Операция сортировки ORDER BY STOPKEY - более эффективная операция сортировки, чем обычная операция ORDER BY.Я не уверен, как работает WINDOW SORT PUSHED RANK, но, похоже, он работает аналогичным образом.

Глядя на v $ sql_workarea после выполнения обоих запросов, для обоих требуется только sort_area в 4096 байт.

Напротив, если я выполнил запрос без пейджингового запроса:

select owner, object_name, object_id
from large_t
order by object_id

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

Обычно, если вы хотите эффективно возвратить TOP N отсортированного запроса, вам понадобится индекс для столбца сортировки - это предотвратит сортировку Oracle вообще.Итак, я создал индекс для OBJECT_ID, а затем снова объяснил оба запроса.

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

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

4 голосов
/ 18 июля 2012

Помимо других отличий, упомянутых в ответах, вы также должны учитывать производительность.Здесь есть неавторизованный, но очень интересный отчет, сравнивающий различные способы нумерации страниц, среди которых использование ROWNUM по сравнению с ROW_NUMBER() OVER():

https://web.archive.org/web/20160901191310/http://www.inf.unideb.hu:80/~gabora/pagination/results.html

0 голосов
/ 16 августа 2011

Чтобы получить свои собственные эмпирические результаты:

-- Create test table
CREATE TABLE test_large_tab (
  tlt_id   NUMBER,
  tlt_data VARCHAR2(50)
);

-- Load with data
BEGIN
   FORALL i IN 1 .. 1000000
      INSERT INTO test_large_tab
      (
       tlt_id,
       tlt_data
      )
      VALUES
      (
       i,
       TO_CHAR(sysdate-i, 'FMMon ddth, YYYY')
      );
END;

Конечно, вы можете увеличить размер таблицы в соответствии с вашими целями тестирования!

Установить время и выполнить оба запроса кбольшая таблица.

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

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

...