Медленный внутренний 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.