Медленный внутренний N-выбор в Oracle

В последнее время у меня возникла проблема. Мы хотели получить таблицу данных из базы данных Oracle в пакетном режиме, где пакет, например, 4-5000. Мое предыдущее "общее" решение заключалось в том, чтобы заключить выбор в какую-то следующую вещь:

SELECT * FROM (
    SELECT ROWNUM AS RN, INNERSELECT.* FROM (
        select THINGS1, THINGS2 from MYTABLE)
    )
INNERSELECT WHERE ROWNUM < 4001) WHERE RN >= 3001

Казалось бы, медленный, так как когда границы rownum высоки (например, 4-500.000), тогда выбор займет более 10-20 секунд. И время линейно увеличивается, когда я увеличиваю значения. Конечно, я знаю почему, поэтому я хотел найти другое решение для получения данных в пакетном режиме, но с гарантированным периодом времени. Ну тогда я использовал этот вид выбора:

SELECT * FROM (
  SELECT INNERSELECT.*, ROW_NUMBER() OVER (ORDER BY INNERSELECT.ROWID) RN FROM 
    ( select THINGS1, THINGS2 from MYTABLE)
    INNERSELECT
) WHERE RN BETWEEN 3001 AND 4000;

Это немного медленно (для получения пакета данных для теста потребовалось 3-4 секунды), но я мог бы увеличить размер пакета без заметного падения производительности, и оно будет таким же для высоких значений. Текущая проблема заключается в том, что я выбираю из нескольких таблиц в нескольких потоках из БД, и производительность падает до чертиков, если я просто использую 3 потока (и мы не говорим о 16, которые в настоящее время используются для проекта). Соединения JDBC объединяются, падение производительности происходит на стороне сервера. Я думаю, что очевидно, что селект потребляет процессорное время, поэтому я ничего не могу сделать, но я надеюсь, что у всех вас есть некоторые советы или подсказки, как оптимизировать это.

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

Спасибо за ответы заранее

2 ответа

Решение

При условии, что MYTABLE имеет числовой первичный ключ IDодной тактикой было бы, чтобы каждый из 16 потоков выполнял этот запрос:

SELECT THINGS1, THINGS2
FROM   MYTABLE
WHERE  MOD(ID,15) = :THREAD_NUMBER

Каждый поток получит уникальное значение для :THREAD_NUMBER от 0 до 15. Это означает, что каждый поток получит (приблизительно) 1/16 строки.

SELECT * FROM (
  SELECT INNERSELECT.*, ROW_NUMBER() OVER (ORDER BY INNERSELECT.ROWID) RN FROM 
    ( select THINGS1, THINGS2 from MYTABLE)
    INNERSELECT
) WHERE RN BETWEEN 3001 AND 4000;

(выберите THINGS1, THINGS2 из MYTABLE)

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

ЗАКАЗАТЬ INNERSELECT.ROWID

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

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

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