Медленная вставка MySQL / MariaDB после сотен миллионов данных - PullRequest
0 голосов
/ 21 января 2019

Я работаю над проектом, который требует от меня создания миллиардов уникального кода. В настоящее время я использую MariaDB с движком InnoDB и python для генерации случайного уникального кода, вставляя пакет из 5000 уникальных кодов за цикл генерации.

Структура моей таблицы:

row_id int              --primary key + autoincrement
unique_code varchar(10) --unique

Проблема: Вставка становится очень медленной, когда я нажимаю 500.000.000 уникальных кодов, и мне все еще нужно сгенерировать до 3 миллиардов кодов. Перед тем, как набрать столько записей, я могу вставить 300-400 миллионов уникальных кодов всего за несколько часов.

Любая помощь будет оценена, спасибо!

Обновление (22 января '19) Ответ на вопрос Рик Джеймс . Вот несколько примеров сгенерированных кодов:

RLXT$CPS1Y
Y4P$9K70WO
PKSTY9M$FR
T$0VEFL2B1
RX4$MEKVQL

Мой сервер имеет 32 ГБ ОЗУ и относительно быстрый жесткий диск SAS, я думаю, что этого более чем достаточно для моих нужд (или нет?).

По моему опыту, TokuDB медленнее вставлял и боролся до того, как набрал 100 м записей, поэтому в этот раз я пошел в InnoDB.

Что касается транзакции, о которой я упоминал ранее: да, 5000 записей вставляются по одному за раз. Это было так быстро до 150 м кодов, после чего я заметил, что скорость постепенно снижалась по мере роста записи. Сейчас я набираю 800 м кодов, для цикла вставки (5000 записей) требуется от 10 до 15 секунд.

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

Я буду ждать дальнейшего ответа, а пока попробую Предложения Рика . Спасибо!

Ответы [ 2 ]

0 голосов
/ 21 января 2019

Покажите нам образец, скажем, первых 10 значений.

Вот почему вы, вероятно, "врезались в стену" ... Индексы можно разделить (на уровне) на две разновидности:

  • Непрерывный, такой как AUTO_INCREMENT значения или TIMESTAMPs, где вы вставляете строки в хронологическом или даже приблизительно в хронологическом порядке. Эти значения вставляются в «конец» таблицы или индекса и попадают только в последний блок (или несколько блоков) BTree. Имея всю активность всего в нескольких блоках, вы получаете мало операций ввода-вывода.

  • Случайные, такие как UUID, MD5 и другие «случайные» значения, предположительно включая ваши. В этом случае «следующее» значение для вставки в таблицу / индекс вряд ли все еще будет кэшироваться в ОЗУ. Так что ввод / вывод нужен. Несмотря на то, что таблица не слишком большая, все блоки индекса могут храниться в оперативной памяти, поэтому требуется небольшой ввод-вывод. Но после того, как индекс становится больше кеша, чаще всего для добавления значения «следующий» потребуется ввод / вывод. Ваш процесс будет становиться все медленнее и медленнее.

Что делать?

План A: добавить «случайный» индекс после , вставив все строки. Добавление индекса будет очень медленным, но, вероятно, быстрее в долгосрочной перспективе, поскольку он может использовать другой алгоритм.

План Б: Не создавайте все значения заранее. Вместо этого создайте следующий, когда вам это нужно.

План C: Купите достаточно ОЗУ, чтобы полностью хранить «случайный» индекс в ОЗУ. (Планируйте примерно в 2 раза больше размера индекса.)

План D: Вы пробовали TokuDB? Я ожидаю, что он выживет дольше, прежде чем он попадет в серьезные неприятности. Каким был ваш опыт.

Вы упомянули транзакции. Пожалуйста, дополните. Вы имели в виду, что каждые 5000 кодов были INSERTed в транзакции? Это, вероятно, оптимально.

Какую кодировку и сопоставление вы используете для своего уникального номера? Вам, вероятно, следует использовать ascii и ascii_bin - для скорости и во избежание проблем с свертыванием регистра.

И ... Вот еще одна мысль о том, как их генерировать. Вам не нужно будет проверять уникальность, так как они будут сгенерированы уникально:

Думайте о ваших 10-символьных строках как о числах, закодированных в кодировке целых чисел base-95. (или сколько угодно разных символов, которые вы разрешаете). Мы будем генерировать числа последовательно, преобразовывать их в строки, а затем рандомизировать их.

Значение «next» вычисляется как случайное значение после значения «current». Случайное значение должно быть от 1 до некоторого приращения, которое может составлять около миллиарда (это зависит от того, сколько чисел вы в конечном итоге хотите, кодировка и т. Д.)

INSERT пакетов по 5 КБ (или чего-либо другого) в таблицу MyISAM, которая не имеет индексов.

Когда закончите, сделайте это:

CREATE TABLE real (
    id ... AUTO_INCREMENT, -- do you really need this??
    random CHAR(10), NOT NULL CHARSET ascii COLLATE ascii_bin,
    PRIMARY KEY(id),   -- what for?
    INDEX(random)   -- uniqueness has been checked
INSERT INTO real (random)
    SELECT random FROM myisam_table
        ORDER BY RAND();

Вот как это будет работать:

  1. Извлекает все «случайные» строки из практически плоского файла (таблица MyISAM).
  2. Используйте unix sort для их шифрования.
  3. INSERT их в таблицу real, последовательно создавая ids.

Примечание: это создаст огромную таблицу отмен, поэтому убедитесь, что на диске много места.

Что касается моих комментариев об отмене id, UNIQUE и т. Д., Пожалуйста, предоставьте информацию о том, как вы намереваетесь использовать real, чтобы я мог согласиться или оспорить их необходимость.

Другой план

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

Таблица будет иметь только один столбец, unique_code CHAR(10) CHARSET ascii PRIMARY KEY.

0 голосов
/ 21 января 2019

Попробуйте MySQL INDEXES (если конфигурация вашего сервера не очень хорошая, нужно обновить размер оперативной памяти и т. Д.)

...