В стандарте рассматриваются два обстоятельства, при которых продлевается время жизни временного:
§12.2 / 4 Существует два контекста, в которых временные объекты уничтожаются в другой точке, чем конец fullexpression. Первый контекст - это когда выражение появляется как инициализатор для декларатора, определяющего объект. В этом контексте временное, которое содержит результат выражения, сохраняется до завершения инициализации объекта. [...]
§12.2 / 5 Второй контекст - это когда ссылка привязана к временному. [...]
blockquote>Ни один из этих двух не позволяет продлить время жизни временного путем более позднего связывания ссылки с другой ссылкой на константу. Но игнорируйте стандартное и думайте о том, что происходит:
Временные ряды создаются в стеке. Ну, технически, вызывающая конвенция может означать, что возвращаемое значение (временное), которое вписывается в регистры, может даже не создаваться в стеке, но нести меня. Когда вы привязываете постоянную ссылку на временный, компилятор семантически создает скрытую именованную переменную (поэтому конструктор копирования должен быть доступен, даже если он не вызывается) и связывает ссылку на эту переменную , Будет ли копия фактически сделана или удалена, является деталью: у нас есть неназванная локальная переменная и ссылка на нее.
Если стандарт разрешил ваш прецедент, то это будет означать, что время жизни временного объекта должно быть расширено до последней ссылки на эту переменную. Теперь рассмотрим это простое расширение вашего примера:
B * f () {B * bp = new B (A ()); return b; } void test () {B * p = f (); delete p; }
Теперь проблема заключается в том, что временная (давайте называть ее
_T
) связана вf ()
, она ведет себя как a там есть локальная переменная. Ссылка связана внутри* bp
. Теперь время жизни объекта выходит за пределы функции, создавшей временную, но поскольку_T
не было динамически распределено, это невозможно.Вы можете попытаться обосновать усилия, которые потребуются для продлить время жизни временного в этом примере, и ответ заключается в том, что он не может быть выполнен без какой-либо формы GC.
Я знаю, что другие упомянули об этом, и вы не хотите его слышать, но используйте SQL * Loader или внешние таблицы . Мое среднее время загрузки для таблиц примерно одинаковой ширины составляет 12,57 секунд для строк более 10 м. Эти утилиты были явно разработаны для быстрой загрузки данных в базу данных и очень хороши в этом. Это может привести к дополнительным штрафным санкциям в зависимости от формата входного файла, но есть довольно много вариантов, и мне редко приходилось менять файлы до загрузки.
Если вы не хотите этого делать это тогда вам не нужно обновлять свое оборудование; вам необходимо удалить все возможные препятствия для быстрой загрузки. Чтобы перечислить их, удалите:
При всем этом вы обязываете базу данных выполнять больше работы, и потому что вы делаете это транзакционно, вы не используете базу данных в полном объеме.
Загрузите данных в отдельную таблицу, скажем ABC_LOAD
. После того, как данные были полностью загружены, выполните инструкцию single INSERT в ABC.
insert into abc
select abc_seq.nextval, a.*
from abc_load a
Когда вы это сделаете (и даже если вы этого не сделаете) убедитесь, что кеш последовательности размер правильный; , чтобы указать :
Когда приложение обращается к последовательности в кеше последовательности, порядковые номера читаются быстро. Однако, если приложение обращается к последовательности, которая не находится в кеше, последовательность должна считываться с диска в кеш, прежде чем будут использоваться порядковые номера.
Если ваши приложения используют много последовательностей одновременно, кеш последовательности может быть недостаточно большим для хранения всех последовательностей. В этом случае доступ к номерам последовательностей может часто требовать чтения с диска. Для быстрого доступа ко всем последовательностям убедитесь, что в вашем кеше достаточно записей для хранения всех последовательностей, используемых одновременно вашими приложениями.
blockquote>Это означает, что если у вас есть 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
Используйте утилиты, которые поставляются с базой данных.
Если вы не можете использовать их, то избавитесь от всего, что может замедлить вставку и сделать это навалом, потому что это то, что база данных хороша.
Если у вас есть текстовый файл, вы должны попробовать SQL LOADER с прямым путем. Это очень быстро, и он предназначен для такого рода массивных нагрузок данных. Посмотрите на опции , которые могут улучшить производительность.
В качестве вторичного преимущества для ETL, ваш файл в ясном тексте будет меньше и легче проверять, чем вставки 10 ^ 7.
Если вам нужно сделать какое-то преобразование, вы можете сделать это с помощью оракула.
Вы должны попробовать вставить свои данные. С этой целью вы можете использовать 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())
{ ... }
DBMS_DATAPUMP
expdp / impdp использует этот API для выполнения своих задач.
– zaratustra
14 July 2014 в 11:26
Кстати, вы пытались увеличить количество физических клиентов, а не только потоков? Работа в облаке на нескольких виртуальных машинах или на нескольких физических машинах. Недавно я читал комментарии, которые я думаю от разработчиков Aerospike, где они объясняют, что многие люди не могут воспроизвести свои результаты только потому, что не понимают, что не так просто заставить клиента фактически отправлять столько запросов в секунду (выше 1 М в секунду в их дело). Например, для их теста они должны были запускать 4 клиента параллельно. Может быть, этот конкретный драйвер oracle просто не достаточно быстрый, чтобы поддерживать более 7-8 тысяч запросов в секунду на одной машине?