Нужен MySQL INSERT - запрос SELECT для таблиц с миллионами записей - PullRequest
1 голос
/ 19 марта 2009

Я пытаюсь сделать шаг к оптимизации таблицы 90GB +:

Старая таблица

Каждый день стол захватывает ок. 750 000 записей из внешнего источника и добавляет их в таблицу с новой датой. Это продолжается уже три года, насколько я понимаю. 97% записей не меняются от одного дня к следующему.

Новая таблица

Я пытаюсь просмотреть старую таблицу (миллионы и миллионы записей) и устранить избыточность, которая, вероятно, значительно уменьшит размер таблицы.

old_table

  • дата
  • record_id
  • data_field (действительно много полей, но для примера)

new_table_index

  • дата
  • index_id

new_table

  • index_id
  • record_id
  • data_field

Логика при каждой записи в old_table

если (record_id не в new_table) или (record_id в new_table, но последняя запись имеет другое поле данных)

вставьте его в new_table и получите index_id

еще

получить последнюю запись index_id для этой записи_id из new_table_index

всегда

вставить index_id и дату в new_table_index

Есть мысли об оптимальных способах сделать это? Я не достаточно продвинут с MySQL, чтобы собрать все это вместе. Когда я попытался написать скрипт на PHP, он использовал 3 ГБ памяти, а затем потерпел крах. Другие предложения или вопросы ??? Большое спасибо!

Ответы [ 4 ]

5 голосов
/ 19 марта 2009

Вы можете использовать это:

new_table
    * date
    * record_id (pk)
    * data_field


INSERT INTO new_table (date,record_id,data_field)
    SELECT date, record_id, data_field FROM old_table
        ON DUPLICATE KEY UPDATE date=old_table.data, data_field=old_table.data_field;

идентификатор записи является первичным ключом, и эту же вставку можно добавить под вставкой в ​​old_table.

см. MySQL

1 голос
/ 19 марта 2009

Прежде всего, я не думаю, что нужно создавать две новые таблицы. Если вам нужен индекс, ну, для этого и нужны индексы MySQL: просто создайте новую таблицу и установите индекс для ее поля date.

Простой скрипт должен это сделать (при условии автоинкремента для new_table index_id):

INSERT INTO new_table (date, record_id, data_field)
  SELECT
    date,
    record_id,
    data_field
  FROM
    old_table
  GROUP BY
    data_field

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

0 голосов
/ 01 апреля 2009

В итоге я использовал гибрид PHP и MySQL (после слишком большого отклонения вначале):

  • ВСТАВИТЬ ССЫЛКУ В ПРЕДЫДУЩИЙ ДЕНЬ ДЛЯ ВСЕХ ПРЕДЫДУЩИХ ДНЕЙ PR (с помощью INSERT - ВЫБРАТЬ)
  • СРАВНИТЕ PR ПРОТИВ ПРЕДЫДУЩЕГО ДНЯ, ВСТАВИТЬ, ЕСЛИ ИЗМЕНЕНО (используя INSERT - ВЫБРАТЬ)
  • Вставить ссылку для недавно обновленных PR (используя SELECT - php foreach - UPDATE)
  • ДОБАВИТЬ НОВЫЕ PR в КАЖДЫЙ ДЕНЬ (используя INSERT - SELECT)
  • ВСТАВИТЬ ССЫЛКУ ДЛЯ НОВЫХ PR (используя INSERT - ВЫБРАТЬ)

Еще нужно усовершенствовать тот, что с циклом php foreach, но по большей части это сработало! Спасибо за вашу помощь!

0 голосов
/ 19 марта 2009

Вы можете добавить столбец в таблицу, в которой хранится время LastModified. затем триггер On Insert или On Update, чтобы установить это значение на текущее время. Ваш процесс переноса данных может просто захватить те записи, у которых LastMotify превышает ваш последний порт данных.

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

Если вам не нужна почасовая детализация этих проверок, вы можете просто сделать это типом поля Date вместо datetime. Поле будет меньше, поэтому больше из них останется в памяти, и ваш фильтр будет быстрее.

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