Я тестирую производительность вставки Postgres. У меня есть таблица с одним столбцом с номером в качестве типа данных. На это также есть индекс. Я заполнил базу данных с помощью этого запроса:
insert into aNumber (id) values (564),(43536),(34560) ...
Я вставил 4 миллиона строк очень быстро по 10000 за один раз с запросом выше. После того, как база данных достигла 6 миллионов строк, производительность резко снизилась до 1 миллиона строк каждые 15 минут. Есть ли хитрость для увеличения производительности вставки? Мне нужна оптимальная производительность вставки в этом проекте.
Использование Windows 7 Pro на машине с 5 ГБ ОЗУ.
sql
postgresql
bulkinsert
sql-insert
Luke101
источник
источник
Ответы:
См. Заполнение базы данных в руководстве по PostgreSQL, отличную, как обычно, статью Depesz по этой теме, и этот ТАК вопрос .
(Обратите внимание, что этот ответ касается массовой загрузки данных в существующую БД или создания новой. Если вы заинтересованы в восстановлении производительности БД с помощью
pg_restore
илиpsql
выполненииpg_dump
вывода, большая часть этого не применяется с тех пор,pg_dump
иpg_restore
уже выполняет такие вещи, как создание триггеры и индексы после завершения схемы + восстановление данных) .Есть много чего сделать. Идеальным решением было бы импортировать в
UNLOGGED
таблицу без индексов, а затем изменить его на logged и добавить индексы. К сожалению, в PostgreSQL 9.4 нет поддержки смены таблиц сUNLOGGED
зарегистрированных. 9,5 добавляет,ALTER TABLE ... SET LOGGED
чтобы позволить вам сделать это.Если вы можете перевести свою базу данных в автономный режим для массового импорта, используйте
pg_bulkload
.В противном случае:
Отключить любые триггеры на столе
Удалите индексы перед началом импорта, затем создайте их заново. ( Построение индекса за один проход занимает гораздо меньше времени, чем постепенное добавление к нему тех же данных, и полученный индекс намного более компактен).
Если вы выполняете импорт в пределах одной транзакции, можно безопасно удалить ограничения внешнего ключа, выполнить импорт и заново создать ограничения перед фиксацией. Не делайте этого, если импорт разбит на несколько транзакций, так как вы можете ввести неверные данные.
Если возможно, используйте
COPY
вместоINSERT
sЕсли вы не можете использовать,
COPY
рассмотрите возможность использования многозначныхINSERT
s, если это возможно. Вы, кажется, уже делаете это. Не пытайтесь перечислить слишком много значений в одномVALUES
; эти значения должны уместиться в памяти пару раз, так что держите их на несколько сотен на оператор.Пакетные вставки в явные транзакции, делая сотни тысяч или миллионы вставок за транзакцию. Практического ограничения AFAIK нет, но пакетирование позволит вам восстановиться после ошибки, отметив начало каждого пакета в ваших входных данных. Опять же, вы, кажется, уже делаете это.
Используйте
synchronous_commit=off
и огромное,commit_delay
чтобы уменьшить затраты fsync (). Это не сильно поможет, если вы сгруппировали свою работу в большие транзакции.INSERT
илиCOPY
параллельно из нескольких соединений. Сколько зависит от дисковой подсистемы вашего оборудования; как правило, вам нужно одно соединение на физический жесткий диск, если используется хранилище с прямым подключением.Установите высокое
checkpoint_segments
значение и включитеlog_checkpoints
. Посмотрите журналы PostgreSQL и убедитесь, что они не жалуются на слишком часто возникающие контрольные точки.Если и только если вы не против потерять весь ваш кластер PostgreSQL (вашу базу данных и все остальные в одном кластере) из-за катастрофического повреждения, если система потерпит крах во время импорта, вы можете остановить Pg, установить
fsync=off
, запустить Pg, выполнить импорт, затем (жизненно) остановите Pg и установитеfsync=on
снова. Смотрите конфигурацию WAL . Не делайте этого, если в какой-либо базе данных вашей установки PostgreSQL уже есть данные, которые вас интересуют. Если вы установите,fsync=off
вы также можете установитьfull_page_writes=off
; опять же, просто не забудьте включить его после импорта, чтобы предотвратить повреждение базы данных и потерю данных. Смотрите недолговечные настройки в руководстве по Pg.Вы также должны посмотреть на настройку вашей системы:
Максимально используйте твердотельные накопители хорошего качества для хранения. Хорошие твердотельные накопители с надежным, защищенным питанием кэшем обратной записи делают скорость фиксации невероятно высокой. Они менее полезны, когда вы следуете совету, который приведен выше - что уменьшает количество дисковых сбросов / количество
fsync()
секунд - но все же может помочь. Не используйте дешевые SSD без надлежащей защиты от сбоя питания, если только вы не заботитесь о сохранности своих данных.Если вы используете RAID 5 или RAID 6 для хранилища с прямым подключением, остановитесь сейчас. Создайте резервную копию данных, реструктурируйте массив RAID в RAID 10 и попробуйте снова. RAID 5/6 безнадежен для массовой записи - хотя хороший RAID-контроллер с большим кешем может помочь.
Если у вас есть возможность использовать аппаратный RAID-контроллер с большим резервным кэшем с резервным питанием от батареи, это действительно может улучшить производительность записи для рабочих нагрузок с большим количеством коммитов. Это не очень помогает, если вы используете async commit с commit_delay или если вы делаете меньше больших транзакций во время массовой загрузки.
Если возможно, сохраните WAL (
pg_xlog
) на отдельном диске / массиве дисков. Нет смысла использовать отдельную файловую систему на одном диске. Люди часто предпочитают использовать пару RAID1 для WAL. Опять же, это больше влияет на системы с высокой частотой фиксации и мало влияет на то, что в качестве цели загрузки данных вы используете незафиксированную таблицу.Вы также можете быть заинтересованы в Оптимизации PostgreSQL для быстрого тестирования .
источник
indisvalid
( postgresql.org/docs/8.3/static/catalog-pg-index.html ) значение false, затем загрузить данные и затем перевести индексы в оперативный режимREINDEX
?UNLOGGED
? Быстрый тест показывает примерно 10-20% улучшение.Использование
COPY table TO ... WITH BINARY
в соответствии с документацией « несколько быстрее, чем формат текста и CSV ». Делайте это только в том случае, если у вас есть миллионы строк для вставки и если вы знакомы с двоичными данными.Вот пример рецепта в Python, использующего psycopg2 с двоичным вводом .
источник
В дополнение к превосходной публикации Крейга Рингера и публикации в блоге depesz, если вы хотите ускорить вставку через интерфейс ODBC ( psqlodbc ) с помощью вставок подготовленных операторов внутри транзакции, вам нужно сделать несколько дополнительных вещей, чтобы сделать ее работать быстро:
Protocol=-1
в строке подключения. По умолчанию psqlodbc использует уровень «Statement», который создает SAVEPOINT для каждого оператора, а не всей транзакции, делая вставки медленнее.UseServerSidePrepare=1
в строке подключения. Без этой опции клиент отправляет весь оператор вставки вместе с каждой вставляемой строкой.SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, reinterpret_cast<SQLPOINTER>(SQL_AUTOCOMMIT_OFF), 0);
SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);
. Нет необходимости явно открывать транзакцию.К сожалению, psqlodbc «реализует»
SQLBulkOperations
, выпуская серию неподготовленных операторов вставки, так что для достижения самой быстрой вставки необходимо вручную кодировать вышеописанные шаги.источник
A8=30000000
в строке подключения также должен использоваться для ускорения вставок.Я потратил около 6 часов на тот же вопрос сегодня. Вставки идут с «обычной» скоростью (менее 3 секунд на 100 КБ) вплоть до 5-ти строк (из 30-ти общих), а затем производительность резко падает (вплоть до 1 минуты на 100 КБ).
Я не буду перечислять все вещи, которые не сработали, и вырезать прямо на мясо.
Я сбросил первичный ключ на целевой таблице (который был GUID), и мои 30MI или строки благополучно перенаправились к месту назначения с постоянной скоростью менее 3 секунд на 100 КБ.
источник
Если вам нужно вставить столбцы с UUID (что не совсем так) и добавить к ответу @Dennis (я пока не могу комментировать), посоветуйте, чем использовать gen_random_uuid () (требуется PG 9.4 и модуль pgcrypto) (a много) быстрее, чем uuid_generate_v4 ()
против
Кроме того, это рекомендуемый официальный способ сделать это
Это время вставки пропущено от ~ 2 часов до ~ 10 минут для 3,7M строк.
источник
Для оптимальной производительности вставки отключите индекс, если это вариант для вас. Помимо этого, лучшее оборудование (диск, память) также полезно
источник
Я также столкнулся с этой проблемой производительности вставки. Мое решение - порождение некоторых процедур go, чтобы закончить вставку. В то же время,
SetMaxOpenConns
должен быть указан правильный номер, в противном случае слишком много ошибок открытого соединения будут предупреждены.Скорость загрузки намного выше для моего проекта. Этот фрагмент кода только что дал представление о том, как он работает. Читатели должны иметь возможность легко изменить его.
источник