Чтобы вставить объемные данные / заполнить базу данных в PostgreSQL, самым быстрым способом было бы использовать COPY. Источник
Я должен заполнить базу данных. Прямо сейчас я получаю скорость записи всего 100-200 в секунду. Это включает в себя отправку многих отдельных вставок через библиотеку C ++ libpqxx. Я полагаю, две причины:
Первый из моих рук. Однако я читал о втором.
Насколько я знаю, для этой цели подходит класс писателей. Однако это, видимо, устарело. Я прочитал, что можно использовать stdin в качестве параметра для копирования.
Но после этих улик я заблудился. Может ли кто-нибудь привести меня к решению?
Редактировать:
Вот код, где у меня есть функция, которая выполняет statemnt:
void pushLog(Log log,pqxx::connection *conn){
pqxx::work w(*conn);
std::stringstream stmt;
stmt<<"INSERT INTO logs VALUES('"<<log.getDevice()<<"','"<<log.getUser()<<"','"<<log.getDate()<<"','"<<log.getLabel()<<"');";
try{
pqxx::result res = w.exec(stmt.str());
w.commit();
}
catch(const std::exception &e){
std::cerr << e.what() << std::endl;
std::cout<<"Exception on statement:["<<stmt.str()<<"]\n";
return;
}
}
Я устанавливаю соединение ранее и передаю ссылку на него.
PS: вопрос может не хватать некоторых деталей. Если это так, пожалуйста, прокомментируйте, и я буду редактировать и добавлять их.
pushLog
Функция фиксирует каждую вставку отдельно, а фиксация выполняется медленно.
Как объяснено в документации Заполнение базы данных:
Если вы разрешите каждую вставку фиксировать отдельно, PostgreSQL будет
делать много работы для каждой строки, которая добавляется
Также:
Дополнительным преимуществом выполнения всех вставок в одной транзакции является
что если вставка одной строки потерпела неудачу, то вставка
все строки, вставленные до этой точки, будут откатываться, так что вы не будете
застрять с частично загруженными данными
В вашем случае, однако, это будет проблемой, а не преимуществом, потому что каждая INSERT может завершиться сбоем при нарушении первичного ключа, тем самым отменяя предыдущие INSERT с момента последней фиксации.
Обратите внимание, что это также будет проблемой с COPY
, если вы используете это.
Поскольку действительно необходимо сгруппировать запросы в транзакциях для повышения производительности, необходимо бороться с нарушениями первичного ключа таким образом, чтобы не прервать транзакцию.
Обычно используются два метода:
Избегайте ошибок: INSERT INTO... WHERE NOT EXISTS (SELECT 1 FROM table WHERE primary_key=...)
Перехватите ошибку, вставив внутрь функцию plpgsql, которая имеет блок EXCEPTION, игнорирующий itr. Конкретные вставки, вызывающие дубликаты, будут отменены, но транзакция не будет прервана.
Если у вас есть одновременные вставки, эти методы должны быть улучшены с помощью стратегии блокировки.
Других решений пока нет …