Как я могу ускорить номер строки в Oracle?
у меня есть 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
но это не дает правильных результатов. Есть ли простой способ ускорить это? Или мне придется потратить еще немного времени на инструмент EXPLAIN?
5 ответов
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
не nullable, или добавить 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
и терпеть неудачу, etc., таким образом, наконец, строки не будут возвращены вообще.
это должно быть обработано, поставив ROWNUM
' s в подзапросе.
похоже на запрос разбиения на страницы.
из этой статьи ASKTOM (около 90% вниз по странице):
также ваши запросы не где почти то же самое, поэтому я не уверен, что преимущество сравнения затрат одного на другой.
часть проблемы заключается в том, насколько велик промежуток от "начала" до "конца" и где они "живут". Скажем, у вас есть миллион строк в таблице, и вы хотите строки 567,890 до 567,900, тогда вам придется жить с тем фактом, что вам нужно будет пройти через всю таблицу, отсортировать почти все это по id и выяснить, какие строки попадают в этот диапазон.
короче, это очень много работы, поэтому оптимизатор дает ему высокую стоимость.
Это тоже не то индекс может помочь во многом. Индекс даст приказ, но в лучшем случае это даст вам место для начала, а затем вы продолжите читать, пока не доберетесь до 567 900-й записи.
Если вы показываете конечному пользователю 10 элементов за раз, возможно, стоит фактически захватить топ-100 из БД, а затем разбить приложение на 10 кусков.
потратьте больше времени с инструментом объяснить план. Если вы видите сканирование таблицы, вам нужно изменить запрос.
ваш запрос имеет мало смысла для меня. Запрос на идентификатор rowid, кажется, напрашиваешься на неприятности. В этом запросе нет реляционной информации. Это реальный вопрос, с которым у вас возникли проблемы, или пример, который вы придумали, чтобы проиллюстрировать свою проблему?