Oracle выбирает sequence.nextval из двойного звука слишком медленно

Некоторое время назад у меня была проблема с производительностью базы данных для вставки/обновления нескольких миллионов записей с использованием jdbc. Чтобы повысить производительность, я изменил код, чтобы использовать batch. Тогда я решил помониторить код с помощью jprofiler, чтобы узнать, насколько увеличилась производительность... а между тем при мониторинге я обнаружил странную вещь!

введите здесь описание изображения

Как видно из приведенного выше снимка экрана, создание нового идентификатора из последовательности происходит очень медленно. Скриншот настолько нагляден, что я должен сказать, что вторая строка — это запрос inner join к таблице с ~8 миллионами записей с самим собой и некоторыми вычислениями (сравните его время со временем третьего запроса!).

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

CREATE SEQUENCE  "XXXXXXXXXXXX_ID_SEQ"  MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE;

Любая мысль?

p.s. Я думаю, что Hibenate использует последовательности для вставки записей аналогичным образом, и на самом деле я ищу лучшие практики использования последовательностей для повышения производительности нашего проекта, использующего спящий режим. Вышеупомянутая задача jdbc завершена.


person faghani    schedule 06.01.2019    source источник
comment
Генератор последовательности Hibernate по умолчанию получает следующее значение последовательности из базы данных каждые 50 вставок и хранит счетчик в памяти. Таким образом (по умолчанию) в 50 раз быстрее, чем то, что вы там видите.   -  person JB Nizet    schedule 06.01.2019
comment
Вы имеете в виду третью строку сверху на этом принтскрине? Среднее время = 396 мкс. мкс = микросекунда. 396 мкс = 0,4 мс (миллисекунды). Это 2500 операций в секунду. Вы действительно думаете, что это медленно? Считаю пустой тратой времени на такую ​​микрооптимизацию, при уменьшении времени на 50% вы выиграете максимум 0,2 мс на одну операцию.   -  person krokodilko    schedule 06.01.2019
comment
Если вам обычно требуется 200 000 значений последовательности для этого процесса, вы можете увеличить размер кэша с 20 до нескольких сотен. Также я не знаю Hibernate (или Java), но было бы неплохо, если бы вы могли сгенерировать последовательность как часть insert вместо того, чтобы извлекать ее в отдельной операции (например, вызывать процедуру, которая выполняет всю обработку базы данных и возвращает сгенерированный идентификатор). Начиная с Oracle 12c, вы можете начать использовать столбцы идентификаторов и забыть обо всем этом микроуправлении последовательностями.   -  person William Robertson    schedule 06.01.2019
comment
@WilliamRobertson Рад слышать, что Oracle 12c поддерживает столбец автоматического идентификатора. Я видел это в SQLite!   -  person faghani    schedule 06.01.2019
comment
@krokodilko да, по сравнению с запросами на обновление со средним временем 8 и 9 мкс, я думаю, что 396 мкс очень медленно для запроса, который звучит тривиально, по крайней мере, на первый взгляд! Опять же, по сравнению с большим внутренним соединением с почти равным временем, я считаю, что это слишком медленно. Я не ищу способ сократить время на 50% или 500%, я подозреваю, что я и, вероятно, многие другие пользователи оракула используют последовательности примерно так, как начинающие java-разработчики используют String += вместо использования StringBuilder или StringBuffer! Если да, то вы знаете, что происходит.   -  person faghani    schedule 06.01.2019
comment
@faghani, тогда, пожалуйста, покажите фрагмент кода, когда эта последовательность используется в вашем приложении - если она исходит из Hibernate, то, вероятно, в сопоставлении одного из объектов, использующих эту последовательность, есть аннотации @GeneratedValue + @SequenceGenerator. Если да, то несложно ускорить этот код в 50 раз.   -  person krokodilko    schedule 06.01.2019
comment
Независимо от других способов сделать его более эффективным, было бы интересно увидеть эффект — изолированно — от простого изменения значения CACHE с 20 до, скажем, 1000. Если вы можете легко попробовать это и сообщить о результатах, я уверен, что многие мы сочтем, что это полезная информация.   -  person mathguy    schedule 06.01.2019
comment
Вы говорите о прошедшем времени 1 + минуты, чтобы получить почти 200 000 ключей из последовательности. Вы выбираете Hibernate, что, вероятно, является проблемой. Вы должны управлять массовой вставкой строк без передачи ключа между БД и клиентом. В настоящее время вы просите БД назначить новый ключ, отправить его клиенту, вставить строку и повторить цикл снова - строка за строкой - медленно за медленно!   -  person Marmite Bomber    schedule 07.01.2019


Ответы (1)


Как было предложено в комментариях других, это не генерация чисел, которая требует времени. Рассмотрим приведенный ниже пример, который устраняет сетевые и сетевые задержки из затрат времени.

SQL>  create sequence tst_seq start with 1 increment by 1; 

Sequence created.

SQL> set timing on
SQL> declare
  seqNo number(38,0); 
begin
  loop 
    select tst_seq.nextval into seqNo from dual; 
    exit when seqNo>=100000; 
  end loop; 
end;   2    3    4    5    6    7    8  
  9  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:05.86

без кэширования для генерации 100 000 номеров требуется 5,86 секунды. если вы воспроизведете вышеприведенный тест, вы получите краткую оценку того, чего вы можете достичь, если измените свою реализацию, чтобы исключить дополнительное обращение туда и обратно для порядковых номеров.

person Kristian Saksen    schedule 07.01.2019