FETCH NEXT 5 ROWS ONLY Влияние на производительность предложения Select, которое возвращает 50 миллионов записей

Мне нужно зациклить более 50 миллионов строк в Oracle и выполнить некоторую обработку. Я получаю строки, используя простой запрос «Выбрать и упорядочить по».

Сначала я использовал программу чтения JDBC на основе курсора, чтобы не получать все результаты сразу, а получать их по мере продвижения цикла. Однако запрос выбора вызвал еще одну проблему, когда Oracle выдал ошибку ORA-01652: unable to extend temp segment by 128 in tablespace TEMP, вероятно, потому, что он не может хранить набор результатов запроса выбора в пространстве TEMP.

Другой вариант, который у меня есть, — это разбиение на страницы набора ключей. Чтобы прочитать первую страницу, я прикреплю следующее предложение FETCH NEXT 5000 ROWS ONLY в конце того же запроса Select, о котором я упоминал выше.

Вопрос: Будет ли это работать? Или я получу тот же результат, потому что ему все равно придется пройти и получить все результаты и получить первые 5000 строк?

Цикл более 50 миллионов строк означает использование языка программирования. ПЛ/SQL? Разве вы не можете делать то, что хотите, с помощью простого SQL?

Thorsten Kettner 03.04.2024 17:53

Мне также нужно сделать вызов API для обработки данных, которые я делаю из процесса Java.

humbleCoder 04.04.2024 07:00

Вы также можете использовать SQL в вызове API. И просто чтобы дать вам представление о том, о чем я говорю: если бы я хотел обновить статус всех продуктов, когда они встречаются в 50 миллионах строк позиций заказа, я бы мог update product set status = 'ordered' where product_id in (select product_id from order_position). Поэтому вместо того, чтобы использовать язык программирования для циклического перебора 50 миллионов позиций заказов и обработки продуктов, я просто использую SQL, который в миллион раз быстрее. Это, конечно, просто пример. Что вы делаете с этими 50 миллионами строк в цикле? Разве ты не можешь использовать SQL?

Thorsten Kettner 04.04.2024 08:42

Хорошо, это фиктивный пример, потому что я не могу разместить здесь реальный код, потому что нам это не разрешено. Мы делаем гораздо больше в процессе до и после вызова API, требуя определенных библиотек со встроенной логикой. Но я не знал, что мы можем сделать вызов API из PLSQL, поскольку я когда-либо использовал только для простых вещей.

humbleCoder 04.04.2024 12:21

API — это набор функций. Вы можете написать кучу функций PL/SQL и назвать это API. Или используйте любой другой язык программирования, имеющий интерфейс SQL (я думаю, что большинство из них имеют). И все, что я говорю, это то, что с базой данных вы обычно не обрабатываете ее с помощью языков программирования в циклах, а скорее используете SQL на основе наборов.

Thorsten Kettner 04.04.2024 12:42

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

humbleCoder 04.04.2024 16:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
200
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Да, использование пагинации набора ключей, скорее всего, поможет вам избежать ошибки ORA-01652, поскольку для получения первых 5000 строк Oracle не требует одновременной загрузки и сортировки всех 50 миллионов строк. Вместо этого он извлекает строки меньшими порциями на основе указанного вами ключа (например, столбца идентификатора), что уменьшает необходимый объем временного хранилища (пространства TEMP).

Вот почему это работает лучше:

Эффективность: разбиение на страницы набора ключей ищет строки только после последней полученной строки, что ускоряет процесс и требует меньше места TEMP. Использование индекса: лучше всего работает, когда у вас есть индекс по столбцу, по которому вы упорядочиваете. Таким образом, Oracle может быстро найти следующий пакет строк, не сканируя всю таблицу. Однако убедитесь, что ваш запрос хорошо оптимизирован, и рассмотрите возможность увеличения табличного пространства TEMP, если вы все еще достигаете ограничений. Кроме того, убедитесь, что столбцы, которые вы используете для сортировки и нумерации страниц, проиндексированы, чтобы ускорить работу и еще больше сократить использование пространства TEMP.

Это создано ИИ?

Marvin 03.04.2024 11:39

я для тебя похож на ай?

julian gommer 03.04.2024 12:01
Ответ принят как подходящий

Пагинация не поможет.

Вы получаете ORA-01652, потому что ваш ORDER BY использует рабочую область, которая перешла из PGA во временное пространство, а ваше табличное пространство TEMP недостаточно велико, чтобы вместить временные сегменты, необходимые для завершения сортировки. 50 миллионов строк и все выбранные столбцы означают очень большие временные сегменты.

Чтобы решить проблему, вы можете выполнить одно из следующих действий:

  1. Попросите вашего администратора базы данных увеличить табличное пространство TEMP (разумный запрос).
  2. Значительно увеличьте использование PGA (с помощью pga_aggregate_target, если v$pgastat.global memory bound < 1 ГБ) или установив политику рабочей области вручную и определив sort_area_size самостоятельно, но это не рекомендуемый метод, поскольку вы можете легко использовать слишком много памяти).
  3. Вы можете переопределить таблицу как IOT (таблица, организованная по индексу), указав свой PK в столбце, по которому вы хотите упорядочить. Тогда ORDER BY должен выполнить сканирование по возрастанию индекса вообще без какой-либо операции сортировки. Обратной стороной является то, что это сканирование индекса, что означает чтение одного блока для следования связанному списку от листового блока к листовому блоку, поэтому оно менее эффективно, чем прямое чтение по пути всего сегмента.
  4. Создание обычного индекса для обычной таблицы-кучи также позволяет избежать сортировки, но она будет работать очень плохо, поскольку каждая строка потребует отдельного чтения блока в сегменте таблицы, а при 50 миллионах строк это будет слишком много. На этом объеме вам потребуется выполнить полное сканирование таблицы, и, поскольку вам нужна операция сортировки, вы захотите, чтобы она была распараллелена.
  5. Убедитесь, что вы используете параллелизм (используйте подсказку parallel с соответствующим DOP). При работоспособном DOP каждый подчиненный PX получает собственное распределение PGA (до 1 ГБ каждый при автоматической политике и 2 ГБ при ручной политике), поэтому вы можете использовать гораздо больше памяти PGA для сортировки (и, следовательно, меньше временного пространства), чем при последовательном процессе. .
  6. Вы можете выполнить собственную «пагинацию», используя предикат WHERE, который собирает только часть необходимых данных и продвигает их программно. Это уменьшает количество входных данных в операцию сортировки и, следовательно, может быть адаптировано к доступному пространству TEMP, но это очень неэффективно, поскольку вам придется повторно сканировать таблицу при каждом запросе. Всегда лучше взять все необходимое за один раз. Хотя вы можете удалить это повторное сканирование с помощью индекса, вы вернетесь к неэффективности, упомянутой выше в пункте 4.
  7. Уменьшите количество извлекаемых столбцов. Вам действительно нужны они все? Любое сокращение столбцов приведет к уменьшению размера временного сегмента, необходимого для сортировки.
  8. Вы также можете вообще исключить ORDER BY. Вам действительно нужны отсортированные результаты? Большинство программных фрагментов этого не делают.

Все вышеизложенное вам следует обсудить со своим администратором базы данных, который должен знать, сколько доступной памяти на хосте(ах) базы данных для PGA, сколько места доступно для расширения TEMP, какую доступность ЦП можно предложить. соответствующий уровень параллелизма (DOP) и т. д.

Будет ли присоединение FETCH NEXT 5000 ROWS ONLY по-прежнему получать все строки в пространство TEMP, или оракул будет управлять этим каким-то образом, как упоминалось в других ответах, используя только идентификаторы и т. д.?

humbleCoder 03.04.2024 16:06

@humbleCoder, FETCH NEXT.. просто выполняет вычисления за вас, но не меняет основную динамику. Если столбец, по которому вы упорядочиваете данные, не индексируется в соответствии с сортировкой, вы будете выполнять полную сортировку 100% таблицы при каждом выполнении, поэтому разбиение на страницы повредит вам из-за повторной сортировки. Если он проиндексирован, чтобы избежать сортировки, вам следует избегать сортировки даже без нумерации страниц, но см. № 4 выше. Вы не хотите использовать индекс на этом томе. Слишком много операций чтения одного блока. Я сам никогда не находил реального применения нумерации страниц в стиле FETCH NEXT, кроме как для отображения пользователем.

Paul W 03.04.2024 16:24

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

humbleCoder 04.04.2024 16:42

Лучше запускать код рядом с данными, а затем запускать данные в коде. Как вы испытали. Java не подходит для манипулирования данными. База данных и SQL есть.

Сказал, что: «FETCH NEXT 5000 ROWS ONLY» приведет к снижению производительности на каждой странице. Например. первые несколько страниц будут быстро светиться. Несколько последних будут загружаться навсегда. Это связано с тем, что механизму базы данных потребуется прочитать 10 000 000 строк, чтобы вернуть строки между 10 000 000 и 10 005 000. Каждый ввод-вывод является дорогостоящим. Вот почему это должно иметь значение.

Стабильную производительность можно получить с помощью правильной индексации и предложения WHERE. Лучшее объяснение, которое я нашел: https://use-the-index-luke.com/blog/2013-07/pagination-done-the-postgresql-way. Пример предназначен для PostgreSQL, но будет работать с любой базой данных.

Для обработки данных я вызываю внешний API. Я не упомянул об этом, потому что думал, что это не имеет значения, но теперь, когда вы упомянули PLSQL, я упомянул об этом.

humbleCoder 04.04.2024 06:59

Да, для нумерации страниц я имею в виду ту же статью. Вопрос в том, будет ли FETCH NEXT 5000 ROWS ONLY с нумерацией страниц (о которой я упоминал в первоначальном вопросе) также замедляться после нескольких страниц?

humbleCoder 04.04.2024 06:59

Чтение 5000 строк всегда будет занимать одинаковое время. Важнейшая часть — быстро найти строку 1, 5001, 10001,... и начать читать интересующую вас 5000 строк. Вот почему так важна правильная индексация. Вы не хотите читать 49005000 строк и бросать их, чтобы найти 49005001 и прочитать последние 5000.

Marcin Badtke 04.04.2024 07:18

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