вставить в оракул DB медленно - JDBC [дублировать]

В стандарте рассматриваются два обстоятельства, при которых продлевается время жизни временного:

§12.2 / 4 Существует два контекста, в которых временные объекты уничтожаются в другой точке, чем конец fullexpression. Первый контекст - это когда выражение появляется как инициализатор для декларатора, определяющего объект. В этом контексте временное, которое содержит результат выражения, сохраняется до завершения инициализации объекта. [...]

§12.2 / 5 Второй контекст - это когда ссылка привязана к временному. [...]

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

Временные ряды создаются в стеке. Ну, технически, вызывающая конвенция может означать, что возвращаемое значение (временное), которое вписывается в регистры, может даже не создаваться в стеке, но нести меня. Когда вы привязываете постоянную ссылку на временный, компилятор семантически создает скрытую именованную переменную (поэтому конструктор копирования должен быть доступен, даже если он не вызывается) и связывает ссылку на эту переменную , Будет ли копия фактически сделана или удалена, является деталью: у нас есть неназванная локальная переменная и ссылка на нее.

Если стандарт разрешил ваш прецедент, то это будет означать, что время жизни временного объекта должно быть расширено до последней ссылки на эту переменную. Теперь рассмотрим это простое расширение вашего примера:

  B * f () {B * bp = new B (A ());  return b;  } void test () {B * p = f ();  delete p;  }  

Теперь проблема заключается в том, что временная (давайте называть ее _T ) связана в f () , она ведет себя как a там есть локальная переменная. Ссылка связана внутри * bp . Теперь время жизни объекта выходит за пределы функции, создавшей временную, но поскольку _T не было динамически распределено, это невозможно.

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

10
задан badola 15 July 2014 в 10:50
поделиться

4 ответа

Я знаю, что другие упомянули об этом, и вы не хотите его слышать, но используйте SQL * Loader или внешние таблицы . Мое среднее время загрузки для таблиц примерно одинаковой ширины составляет 12,57 секунд для строк более 10 м. Эти утилиты были явно разработаны для быстрой загрузки данных в базу данных и очень хороши в этом. Это может привести к дополнительным штрафным санкциям в зависимости от формата входного файла, но есть довольно много вариантов, и мне редко приходилось менять файлы до загрузки.

Если вы не хотите этого делать это тогда вам не нужно обновлять свое оборудование; вам необходимо удалить все возможные препятствия для быстрой загрузки. Чтобы перечислить их, удалите:

  1. Индекс
  2. Триггер
  3. Последовательность
  4. Раздел

При всем этом вы обязываете базу данных выполнять больше работы, и потому что вы делаете это транзакционно, вы не используете базу данных в полном объеме.

Загрузите данных в отдельную таблицу, скажем ABC_LOAD. После того, как данные были полностью загружены, выполните инструкцию single INSERT в ABC.

insert into abc
select abc_seq.nextval, a.*
  from abc_load a

Когда вы это сделаете (и даже если вы этого не сделаете) убедитесь, что кеш последовательности размер правильный; , чтобы указать :

Когда приложение обращается к последовательности в кеше последовательности, порядковые номера читаются быстро. Однако, если приложение обращается к последовательности, которая не находится в кеше, последовательность должна считываться с диска в кеш, прежде чем будут использоваться порядковые номера.

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

Это означает, что если у вас есть 10 потоков, одновременно записывающих 500 записей, каждый из которых использует эта последовательность, то вам нужен размер кеша 5000. В документе ALTER SEQUENCE указано, как это изменить:

alter sequence abc_seq cache 5000

Если вы будете следовать моему предложению, я бы увеличил размер кеша примерно до 10,5 м.

Посмотрите на подсказку APPEND (см. также базу Oracle) ; это инструктирует Oracle использовать вставку прямого пути, которая добавляет данные непосредственно в конец таблицы, а не ищет место для ее размещения. Вы не сможете использовать это, если ваша таблица имеет индексы, но вы можете использовать ее в ABC_LOAD

insert /*+ append */ into ABC (SSM_ID, invocation_id , calc_id, ... )
select 'c','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'a','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'b','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'c','g',NULL, 'test', 123 , 'N', 'asdf' from dual

Если вы используете подсказку APPEND; Я добавил TRUNCATE ABC_LOAD после того, как вы вставили в ABC, иначе эта таблица будет расти бесконечно. Это должно быть безопасным, так как вы закончите использовать таблицу к тому времени.

Вы не указываете, какую версию или версию или Oracle вы используете. Существует несколько дополнительных трюков, которые вы можете использовать:

  • Oracle 12c. Эта версия поддерживает столбцы идентификации ; вы можете полностью избавиться от этой последовательности.
    CREATE TABLE ABC(
       seq_no         NUMBER GENERATED AS IDENTITY (increment by 5000)
    
  • Oracle 11g r2 Если вы сохраняете триггер; вы можете напрямую присвоить значение последовательности.
    :new.seq_no := ABC_seq.nextval;
    
  • Oracle Enterprise Edition Если вы используете Oracle Enterprise, вы можете ускорить INSERT с ABC_LOAD с помощью подсказки PARALLEL :
    insert /*+ parallel */ into abc
    select abc_seq.nextval, a.*
      from abc_load a
    
    Это может привести к собственные проблемы (слишком много параллельных процессов и т. д.), поэтому проверьте. Он может помочь для небольших вставных партий, но это менее вероятно, поскольку вы потеряете время, вычисляя, какой поток должен обрабатывать то, что.

tl; dr

Используйте утилиты, которые поставляются с базой данных.

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

6
ответ дан Ben 15 August 2018 в 19:47
поделиться

Если у вас есть текстовый файл, вы должны попробовать SQL LOADER с прямым путем. Это очень быстро, и он предназначен для такого рода массивных нагрузок данных. Посмотрите на опции , которые могут улучшить производительность.

В качестве вторичного преимущества для ETL, ваш файл в ясном тексте будет меньше и легче проверять, чем вставки 10 ^ 7.

Если вам нужно сделать какое-то преобразование, вы можете сделать это с помощью оракула.

2
ответ дан borjab 15 August 2018 в 19:47
поделиться

Вы должны попробовать вставить свои данные. С этой целью вы можете использовать OCI * ML . Обсуждение этого здесь . Заметная статья здесь . Или вы можете попробовать загрузить Oracle SQL Bulk Loader SQLLDR, чтобы увеличить скорость загрузки. Для этого выполните сериализацию данных в файл csv и вызовите SQLLDR, передавая csv в качестве аргумента.

Еще одна возможная оптимизация - стратегия транзакций. Попробуйте вставить все данные в 1 транзакцию на поток / соединение.

Другой подход заключается в использовании MULTIPLE INSERT :

INSERT ALL
   INTO ABC (SSM_ID, invocation_id , calc_id, analytic_id, analytic_value, 
   override, update_source ) VALUES ('c','b',NULL, 'test', 123 , 'N', 'asdf')
   INTO ABC (SSM_ID, invocation_id , calc_id, analytic_id, analytic_value, 
   override, update_source ) VALUES ('a','b',NULL, 'test', 123 , 'N', 'asdf')
   INTO ABC (SSM_ID, invocation_id , calc_id, analytic_id, analytic_value, 
   override, update_source ) VALUES ('b','b',NULL, 'test', 123 , 'N', 'asdf')

SELECT 1 FROM DUAL;

вместо insert .. union all.

Ваши данные образца выглядят взаимозависимыми, что приводит к вставке 1 значительной строки, а затем ее добавлению в 4 строки с последующим sql-запросом.

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

Использование подготовленного синтаксиса оператора должно ускорить загрузку, так как сервер должен иметь уже проанализированный кешированный оператор.

Затем оптимизируйте свой код на C ++: переместите ops из цикла:

 //! Preparing the Query
   std::string insert_query = "insert into ";
   insert_query += Context::instance().getUpdateTable();
   insert_query += " (SSM_ID, invocation_id , calc_id, 
        analytic_id, analytic_value, override, update_source)\n";
   while (startOffset < statements.size())
   { ... }
1
ответ дан Community 15 August 2018 в 19:47
поделиться
  • 1
    Кроме того, пакет DBMS_DATAPUMP expdp / impdp использует этот API для выполнения своих задач. – zaratustra 14 July 2014 в 11:26
  • 2
    @xacinay. Я уже объединяя все данные в одну транзакцию, используя SQL Query, упомянутый в моем Вопросе. Я бы хотел избежать SQLLDR, так как он выведет контроль из моей программы CPP. Я бы предпочел что-то, что можно сделать в моем приложении на C ++, например, в библиотеке OCI. – badola 14 July 2014 в 11:38
  • 3
    Ну, неясно, сколько записей за транзакцию вы фактически вставляете. Если 500rcs / transaction - сумма довольно мала. Попробуйте увеличить его до 20000rcs / транзакций. – xacinay 14 July 2014 в 12:10
  • 4
    @xacinay Хорошо, когда я отправил 10 миллионов строк, это около 33334 строк в потоке. Затем поток разбивает его на партию 500 или 1000, в соответствии с пользовательским вводом. Я тестировал с различным количеством партий, а также до 5000, но изменение производительности было незначительным. – badola 14 July 2014 в 12:12
  • 5
    Изменен мой ответ (см. Ссылку OCI ML) – xacinay 14 July 2014 в 12:25

Кстати, вы пытались увеличить количество физических клиентов, а не только потоков? Работа в облаке на нескольких виртуальных машинах или на нескольких физических машинах. Недавно я читал комментарии, которые я думаю от разработчиков Aerospike, где они объясняют, что многие люди не могут воспроизвести свои результаты только потому, что не понимают, что не так просто заставить клиента фактически отправлять столько запросов в секунду (выше 1 М в секунду в их дело). Например, для их теста они должны были запускать 4 клиента параллельно. Может быть, этот конкретный драйвер oracle просто не достаточно быстрый, чтобы поддерживать более 7-8 тысяч запросов в секунду на одной машине?

0
ответ дан Maksim Gumerov 15 August 2018 в 19:47
поделиться
  • 1
    Привет @Maskim, я не успел проверить ваш предложенный подход. В конце концов, я закончил использование программ sqlldr, поставляемых в комплекте с Oracle. – badola 5 October 2017 в 13:45
Другие вопросы по тегам:

Похожие вопросы: