Пейджинг с Oracle

Я не так хорошо знаком с Oracle, как хотелось бы. У меня около 250 тыс. Записей, и я хочу отображать их по 100 на странице. В настоящее время у меня есть одна хранимая процедура, которая извлекает все четверть миллиона записей в набор данных с помощью адаптера данных, набора данных и метода dataadapter.Fill (набор данных) для результатов из хранимой процедуры. Если у меня есть целочисленные значения «Номер страницы» и «Количество записей на странице», которые я могу передать в качестве параметров, что было бы наилучшим способом вернуть только этот конкретный раздел. Скажем, если я передам 10 в качестве номера страницы и 120 в качестве количества страниц, из оператора select я получу от 1880-го до 1200-го или что-то в этом роде, моя математика в моей голове может быть отключена.

Я делаю это в .NET с C#, подумал, что это не важно, если я смогу понять это правильно на стороне sql, тогда я должен быть крутым.

Обновление: я смог использовать предложение Брайана, и оно отлично работает. Я хотел бы поработать над некоторой оптимизацией, но страницы появляются через 4–5 секунд, а не за минуту, и мой элемент управления подкачкой смог очень хорошо интегрироваться с моими новыми сохраненными процессами.

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
103
0
126 048
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Ответ принят как подходящий

Примерно так должно работать: Из блога Франса Боумы

SELECT * FROM
(
    SELECT a.*, rownum r__
    FROM
    (
        SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
        ORDER BY OrderDate DESC, ShippingDate DESC
    ) a
    WHERE rownum < ((pageNumber * pageSize) + 1 )
)
WHERE r__ >= (((pageNumber-1) * pageSize) + 1)

Да, это «встроенный» столбец, который поддерживает Oracle, он всегда начинается с 1 и увеличивается для каждой строки. Итак, в этом фрагменте кода, если у вас 1000 строк, применяется порядок сортировки, а затем каждой строке назначается rownum. Внешний выбор (ы) использует эти номера строк для поиска «страницы», которую вы ищете, в зависимости от размера вашей страницы.

Brian Schmitt 20.11.2011 22:54

Это хорошо, но ужасно медленно для больших выборок, просто проверьте, сколько времени будет для выбора от 0 до 1000 и от 500000 до 501000 ... Я использовал такую ​​структуру выбора, теперь я ищу обходной путь.

newhouse 06.08.2012 15:58

@ n3whous3 вы можете попробовать это - inf.unideb.hu/~gabora/pagination/results.html

jasonk 27.08.2012 03:26

Oracle говорит мне, что псевдоним «a» неоднозначен. Есть ли причина, по которой я получаю эту ошибку?

Chris Holmes 01.09.2012 02:04

@ChrisHolmes, вы когда-нибудь получали ответ на свой вопрос. Я получаю ту же ошибку

jim 02.11.2012 21:41

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

Chris Holmes 03.11.2012 19:02

Я задался вопросом, почему два WHERE не могут быть объединены с AND, и тут обнаружил: orafaq.com/wiki/ROWNUM

Mengdi Gao 17.12.2012 10:09

Пагинация Oracle портит мне день.

Aetherus 01.07.2019 11:02

Спросите Тома о разбиении на страницы и очень, очень полезных аналитических функциях.

Это выдержка с той страницы:

select * from (
    select /*+ first_rows(25) */
     object_id,object_name,
     row_number() over
    (order by object_id) rn
    from all_objects
)
where rn between :n and :m
order by rn;

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

tallseth 03.04.2012 20:46

@tallseth Вы правы. На этой странице его сложно найти. Добавлен отрывок.

Chobicus 05.04.2012 12:18

Это правильный ответ, если вы хотите динамически изменять свой заказ.

chakeda 30.08.2018 23:16

Попробуйте следующее:

SELECT *
FROM
  (SELECT FIELDA,
    FIELDB,
    FIELDC,
    ROW_NUMBER() OVER (ORDER BY FIELDC) R
  FROM TABLE_NAME
  WHERE FIELDA = 10
  )
WHERE R >= 10
AND R   <= 15;

via [tecnicume]

В интересах полноты, для людей, ищущих более современное решение, в Оракул 12c есть некоторые новые функции, включая улучшенное разбиение по страницам и верхнюю обработку.

Пейджинг

Пейджинг выглядит так:

SELECT *
FROM user
ORDER BY first_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

Лучшие записи N

Получение топовых записей выглядит так:

SELECT *
FROM user
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY

Обратите внимание, что в обоих приведенных выше примерах запросов есть предложения ORDER BY. Новые команды соблюдают их и запускаются на отсортированных данных.

Мне не удалось найти хорошую справочную страницу Oracle для FETCH или OFFSET, но в эта страница есть отличный обзор этих новых функций.

Представление

Как отмечает @wweicker в комментариях ниже, производительность - это проблема с новым синтаксисом в 12c. У меня не было копии 18c, чтобы проверить, улучшил ли ее Oracle с тех пор.

Интересно, что мои фактические результаты были возвращены немного быстрее, когда я впервые выполнил запросы к своей таблице (более 113 миллионов строк) для нового метода:

  • Новый метод: 0,013 секунды.
  • Старый метод: 0,107 секунды.

Однако, как упоминал @wweicker, план объяснения выглядит намного хуже для нового метода:

  • Стоимость нового метода: 300 110
  • Стоимость старого метода: 30

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

Давайте посмотрим, включает ли один неиндексированный столбец в предыдущий набор данных:

  • Время / стоимость нового метода: 189,55 секунды / 998 908
  • Время / стоимость старого метода: 1,973 секунды / 256

Резюме: используйте с осторожностью, пока Oracle не улучшит эту обработку. Если у вас есть индекс для работы, возможно, вам удастся использовать новый метод.

Надеюсь, у меня скоро будет копия 18c, с которой можно будет поиграть, и я смогу обновить

Это отличный ответ для пользователей 12c

Lalji Gajera 14.02.2019 13:40

Синтаксис чище, но производительность хуже (dba-presents.com/index.php/databases/oracle/…)

wweicker 22.03.2019 18:43

Полезно знать, спасибо @wweicker. Надеюсь, Oracle скоро исправит производительность; хотя, зная Oracle, это может быть далекой надеждой!

JoelC 25.03.2019 16:26

Синтаксис новый и преобразован в обычные вызовы ROW_NUMBER / RANK. Связанные Как ограничить количество строк, возвращаемых запросом Oracle после заказа?

Lukasz Szozda 18.08.2019 22:10

@JoelC изменилось ли ваше мнение?

wattry 01.05.2020 18:41

похоже, что Oracle позаботилась о проблемах с производительностью. смотрите здесь - blogs.oracle.com/optimizer/fetch-first-rows-just-got-faster

Raj 27.12.2020 08:42

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

До oracle 12c не было функциональности OFFSET / FETCH, поэтому взгляните на белая бумага, как предлагал @jasonk. Это самая полная статья о различных методах, которую я нашел, с подробным объяснением преимуществ и недостатков. Чтобы скопировать их сюда, потребуется много времени, поэтому я не буду этого делать.

Также есть хорошая статья от создателей jooq, объясняющая некоторые общие предостережения при разбивке на страницы Oracle и других баз данных. сообщение в блоге jooq

Хорошие новости, начиная с oracle 12c у нас появилась новая функциональность OFFSET / FETCH. Новые возможности OracleMagazine 12c. Пожалуйста, обратитесь к разделу «Топ-N запросов и разбивки на страницы».

Вы можете проверить свою версию оракула, выполнив следующее заявление

SELECT * FROM V$VERSION

В своем проекте я использовал Oracle 12c и Java. Код подкачки выглядит так:

 public public List<Map<String, Object>> getAllProductOfferWithPagination(int pageNo, int pageElementSize, Long productOfferId, String productOfferName) {
    try {

        if (pageNo==1){
            //do nothing
        } else{
            pageNo=(pageNo-1)*pageElementSize+1;
        }
        System.out.println("algo pageNo: " + pageNo +"  pageElementSize: "+ pageElementSize+"  productOfferId: "+ productOfferId+"  productOfferName: "+ productOfferName);

        String sql = "SELECT * FROM ( SELECT * FROM product_offer po WHERE po.deleted=0 AND (po.product_offer_id=? OR po.product_offer_name LIKE ? )" +
             " ORDER BY po.PRODUCT_OFFER_ID asc) foo OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";

       return jdbcTemplate.queryForList(sql,new Object[] {productOfferId,"%"+productOfferName+"%",pageNo-1, pageElementSize});

    } catch (Exception e) {
        System.out.println(e);
        e.printStackTrace();
        return null;
    }

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