Массовая вставка сотен миллионов записей - PullRequest
4 голосов
/ 16 мая 2010

Какой самый быстрый способ вставить 237 миллионов записей в таблицу с правилами (для распределения данных по дочерним таблицам)?

Я пробовал или рассматривал:

  1. Вставить утверждения.
  2. Транзакционные вставки (BEGIN и COMMIT).
  3. Команда COPY FROM.
  4. http://pgbulkload.projects.postgresql.org/

Вставки выполняются слишком медленно (четыре дня), а COPY FROM игнорирует правила (и возникают другие проблемы).

Пример данных:

station_id,taken,amount,category_id,flag
1,'1984-07-1',0,4,
1,'1984-07-2',0,4,
1,'1984-07-3',0,4,
1,'1984-07-4',0,4,T

Структура таблицы (с одним включенным правилом):

CREATE TABLE climate.measurement
(
  id bigserial NOT NULL,
  station_id integer NOT NULL,
  taken date NOT NULL,
  amount numeric(8,2) NOT NULL,
  category_id smallint NOT NULL,
  flag character varying(1) NOT NULL DEFAULT ' '::character varying
)
WITH (
  OIDS=FALSE
);
ALTER TABLE climate.measurement OWNER TO postgres;

CREATE OR REPLACE RULE i_measurement_01_001 AS
    ON INSERT TO climate.measurement
   WHERE date_part('month'::text, new.taken)::integer = 1 AND new.category_id = 1 DO INSTEAD  INSERT INTO climate.measurement_01_001 (id, station_id, taken, amount, category_id, flag)
  VALUES (new.id, new.station_id, new.taken, new.amount, new.category_id, new.flag);

Данные изначально были в MySQL, но должны быть переключены на PostgreSQL для повышения производительности (и для использования расширения PL / R).

Спасибо!

Ответы [ 3 ]

11 голосов
/ 16 мая 2010

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

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

Например, ваше правило использует date_part () для извлечения месяца из даты, поэтому для определения дочерней таблицы postgres должен проанализировать строку даты, преобразовать ее в метку времени, а затем преобразовать метку времени обратно в календарь, чтобы снова вернуть поле месяца. Но если вы пишете что-то, чтобы сделать это заранее, вы можете просто сделать substr($date,5,2) (или эквивалент): что, по вашему мнению, будет быстрее?

Это также возможность очистить формат данных, чтобы COPY приняла его. Обратите внимание, что вы можете указать столбцы с помощью команды COPY: если вы не сделали этого с этой схемой и файлом примера, вы получите ошибки из-за дополнительного столбца «id» на передней панели. («copy from ... with csv header», возможно, понял это, но, возможно, нет… опция «header» может просто пропустить первую строку).

Я только что загрузил около 280e6 строк в экземпляр postgresql сам за несколько часов, так что это, конечно, не невозможно. Для этой начальной загрузки я выключил fsync =; План состоит в том, чтобы загрузить резерв, а затем снова включить его для регулярных ежедневных нагрузок. Мне пришлось установить checkpoint_segments = 40, чтобы избежать получения предупреждений о контрольных точках в журналах. Это просто загружается на мой компьютер разработчика - я использую выделенный диск для базы данных, который отличается от диска, используемого для xlogs (то есть я создал табличное пространство на большом диске и создал базу данных внутри этого табличного пространства). В экземпляре для shared_buffers установлено значение 1 ГБ, а для checkpoint_target установлено значение 0.5. Я попытался загрузить некоторые разделы параллельно, и это не дало особых улучшений, поэтому я подозреваю, что медленный диск является узким местом, а не самой БД.

Осталось еще 1.7e9 строк ... Надеюсь, завтра закончим.

3 голосов
/ 01 сентября 2011
  1. создать родительскую таблицу без индекса, только столбец и его типы (создать таблицу some_data (c_1 int, c_2 varchar, ....))
  2. создать последовательность для перечисления новых таблиц данных
  3. взять новый идентификатор из последовательности
  4. создать новую таблицу для реальных данных с помощью ключевого слова like (создать таблицу some_data_X like some_data)
  5. вставить реальные данные в some_data_X с копией в двоичном формате
  6. создание индексов, временных ограничений и т. Д. (Расширение возможностей ваших ядер с помощью нескольких подключений к postgresql)
  7. наследовать родительскую таблицу
  8. теперь готов к выбору! Таким образом, я достиг 400000-500000 вставок в секунду с созданием индекса на 10 столбцах (2 xeon, 24 ядра, 24 ГБ памяти, SSD).

Бонус: в отдельном потоке удалить старые данные (some_data_X с min X): огромный круговой буфер с индексацией!

0 голосов
/ 17 мая 2010

Документация PostgreSQL содержит страницу , заполняющую базу данных , которая может помочь вам, если вы следовали советам araqnid, чтобы предварительно обработать ввод, чтобы вы могли использовать COPY.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...