Вопрос

Представьте себе таблицу со следующей структурой на PostgreSQL 9.0:

create table raw_fact_table (text varchar(1000));

Для упрощения я упоминаю только один текстовый столбец, в действительности у него дюжина. Эта таблица имеет 10 миллиардов строк, и в каждом столбце много дубликатов. Таблица создана из плоского файла (CSV) с использованием копии из.

Чтобы повысить производительность, я хочу преобразовать в следующую структуру звездных схем:

create table dimension_table (id int, text varchar(1000));

Таблица фактов будет заменена на таблицу фактов, например, на следующее:

create table fact_table (dimension_table_id int);

Мой текущий метод состоит в том, чтобы по существу запустить следующий запрос, чтобы создать таблицу измерений:

Create table dimension_table (id int, text varchar(1000), primary key(id));

Затем для создания таблицы измерений, которую я использую:

insert into dimension_table (select null, text from raw_fact_table group by text);

После этого мне нужно запустить следующий запрос:

select id into fact_table from dimension inner join raw_fact_table on (dimension.text = raw_fact_table.text);

Представьте себе ужасное представление, которое я получаю, сравнивая все строки со всеми другими строками несколько раз.

На MySQL я мог запустить хранимую процедуру во время копии. Это может создать хэш строки, и все последующее сравнение строк проводится на хэш вместо длинной необработанной строки. Это не может быть возможно на PostgreSQL, что мне тогда делать?

Пример данных будет файл CSV, содержащий что -то подобное (я использую цитаты также вокруг целых чисел и удвоений):

"lots and lots of text";"3";"1";"2.4";"lots of text";"blabla"
"sometext";"30";"10";"1.0";"lots of text";"blabla"
"somemoretext";"30";"10";"1.0";"lots of text";"fooooooo"
Это было полезно?

Решение

Просто на вопросы: - Необходимо преобразовать ваши данные в 1 или 2 шагах? - Можем ли мы изменить таблицу во время преобразования?

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

Один подход будет:

  1. Создать Dimension_table (если я правильно его понимаю, у вас нет проблем с производительностью) (возможно, с дополнительным временным логическим полем ...)
  2. Повторите: выберите один ранее не выбранный вход из Dimension_Table, выберите все строки из RAW_FACT_TABLE, содержащего его, и вставьте их в FACT_TABLE. Mark Dimension_table записи как сделано, и затем ... вы можете написать это как хранимую процедуру, и она может преобразовать ваши данные в фоновом режиме, употребление минимальных ресурсов ...

Или другой (вероятно, лучше):

  1. Создайте fact_table как каждую запись из RAW_FACT_TABLE и One Dimension_ID. (Так включая Dimension_Text и Dimension_id Rows)
  2. Создать Dimension_table
  3. Создайте триггер после вставки для fact_table, который:
    • Поиск Dimension_Text в fact_table
    • Если не найдено, создает новую запись в dimension_table
    • Обновления dimension_id до этого идентификатора
  4. В петле Simle вставьте каждую запись из RAW_FACT_TABLE в FACT_TABLE

Другие советы

Представьте себе ужасное представление, которое я получаю, сравнивая все строки со всеми другими строками несколько раз.

Когда вы делаете это некоторое время, вы перестаете представлять производительность, и начинаете измерять ее. «Превосходная оптимизация - это корень всего зла».

Что значит для вас "миллиард"? Для меня в США это означает 1 000 000 000 (или 1E9). Если это также верно для вас, вы, вероятно, смотрите на 1-7 терабайт данных.

Мой текущий метод состоит в том, чтобы по существу запустить следующий запрос, чтобы создать таблицу измерений:

Create table dimension_table (id int, text varchar(1000), primary key(id));

Как вы собираетесь поместить 10 миллиардов строк в таблицу, которая использует целое число для первичного ключа? Допустим, что половина рядов - дубликаты. Как эта арифметика работает, когда вы это делаете?

Не представляйте себе. Читать первое. Затем тест.

Читать Хранилище данных с PostgreSQL. Анкет Я подозреваю, что эти слайды презентаций дадут вам несколько идей.

Также читайте Заполнение базы данных, и подумайте, какие предложения для реализации.

Проверьте с миллионом (1E6) рядами, после процесса «разделяй и завоевание». То есть не пытайтесь загружать миллион за раз; Напишите процедуру, которая разбивает ее на более мелкие куски. Бежать

EXPLAIN <sql statement>

Вы сказали, что оцениваете как минимум 99% дубликатов строк. Вообще говоря, есть два способа избавиться от дупсов

  1. Внутри базы данных, не обязательно ту же платформу, которую вы используете для производства.
  2. За пределами базы данных, в файловой системе, не обязательно та же самая файловая система, которую вы используете для производства.

Если у вас все еще есть текстовые файлы, которые вы загрузили, я бы сначала рассмотрел попытку вне базы данных. Этот Awk One-Liner выведет уникальные строки из каждого файла. Это относительно экономично, поскольку он делает только один проход по данным.

awk '!arr[$0]++' file_with_dupes > file_without_dupes

Если у вас действительно 99% Dupes, к концу этого процесса вы должны были уменьшить ваши 1-7 терабайт до примерно 50 концертов. И, сделав это, вы также можете читать каждую уникальную строку и создать файл, определенный вкладок, прежде чем копировать его в хранилище данных. Это еще одна одна строка:

awk '{printf("%d\t%s\n", NR, $0);}' file_without_dupes > tab_delimited_file

Если бы вам нужно было сделать это под окнами, я бы использовал Cygwin.

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

Но я бы проверил

SELECT DISTINCT ...

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

В конце вы пропускаете некоторые детали, но я не вижу, что там обязательно проблема. Нет доказательства того, что все строки на самом деле сравниваются со всеми другими строками. Если вы сделаете присоединение, PostgreSQL вполне может выбрать более разумный алгоритм присоединения, такой как хэш -соединение, которое может дать вам то же самое хэшинг, что вы реализуете себя в своем решении MySQL. (Опять же, ваши данные туманны.)

-- add unique index
CREATE UNIQUE INDEX uidx ON dimension_table USING hash(text);
-- for non case-sensitive hash(upper(text))

попробовать хэш (текст); и btree (текст), чтобы увидеть, какой из них быстрее

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

Вставьте в Dimension_Table (выберите NULL, MD5 (текст), текст из группы raw_fact_table по тексту)

Добавьте поле MD5 в RAW_FACT_TABLE, а также выберите ID в FACT_TABLE из Dimension Inner Mocient vaw_fact_table ON (Dimension.md5 = RAW_FACT_TABLE.MD5);

Индексы на поданный MD5 также могут помочь

Или вы можете рассчитать MD5 на лету при загрузке данных. Например, наш процессор ETL Industranced ETL может сделать это для вас. Кроме того, он может загружать данные в несколько таблиц в то же время.

Наш веб-сайт, например, на нашем веб-сайте, например, на нашем веб-сайте доступен ряд учебных пособий.

http://www.dbsoftlab.com/online-tutorials/advanced-etl-processor/advanced-etl-processor-working-with-slow-changing-dimension-part-2.html

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top