Вопрос

У меня есть SQL-запрос, который выглядит примерно так:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

По сути, именно ПОРЯДОК действий ПО частям замедляет процесс.Если бы я удалил его, стоимость ОБЪЯСНЕНИЯ снизилась бы на порядок (более чем в 1000 раз).Я уже пробовал это:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

Но это не дает правильных результатов.Есть ли какой-нибудь простой способ ускорить это?Или мне придется потратить еще немного времени на инструмент ОБЪЯСНЕНИЯ?

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

Решение

ROW_NUMBER довольно неэффективен в Oracle.

Подробнее о производительности читайте в статье в моем блоге:

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

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

Этот запрос будет использовать COUNT STOPKEY

Также либо убедитесь, что вы column не обнуляется и не добавляет WHERE column IS NOT NULL состояние.

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

Обратите внимание, что вы не можете использовать ROWNUM BETWEEN :start and :end без подзапроса.

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

Если вы используете ROWNUM BETWEEN 10 and 20, первая строка, удовлетворяющая всем остальным условиям, станет кандидатом на возвращение, временно назначенным с ROWNUM = 1 и провалить испытание на ROWNUM BETWEEN 10 AND 20.

Тогда следующей строкой будет кандидат, которому присвоен ROWNUM = 1 и сбой и т.д., так что, в конце концов, строки вообще не будут возвращены.

Это следует обойти, поставив ROWNUMэто входит в подзапрос.

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

Похоже, запрос на нумерацию страниц.

Из этой статьи ASKTOM (около 90% вниз по странице):

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

Кроме того, ваши запросы не совпадают, поэтому я не уверен, в чем заключается преимущество сравнения затрат одного на другое.

Ваш столбец ORDER BY проиндексирован? Если нет, то это хорошее место для начала.

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

Короче говоря, это большая работа, поэтому оптимизатор стоит дорого.

Индекс также не очень помогает. Индекс дает порядок, но в лучшем случае дает вам место для начала, а затем вы продолжаете читать, пока не дойдете до 567 900-й записи.

Если вы показываете своему конечному пользователю по 10 элементов за раз, возможно, стоит извлечь 100 лучших из БД, а затем разбить эти 100 на десять частей приложения.

Проводите больше времени с инструментом EXPLAIN PLAN. Если вы видите TABLE SCAN, вам нужно изменить свой запрос.

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

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