Удаление миллионов строк в MySQL - PullRequest
63 голосов
/ 23 августа 2009

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

  1. Напишите скрипт, который будет выполнять тысячи небольших запросов на удаление в цикле. Теоретически это позволит обойти проблему с заблокированной таблицей, поскольку другие запросы смогут поместить ее в очередь и выполнить между удалениями. Но это все равно будет сильно увеличивать нагрузку на базу данных и займет много времени.
  2. Переименуйте таблицу и воссоздайте существующую таблицу (теперь она будет пустой). Затем сделайте мою уборку на переименованном столе. Переименуйте новую таблицу, назовите старую обратно и объедините новые строки в переименованную таблицу. Этот способ требует значительно больше шагов, но должен выполнять работу с минимальными перерывами. Единственная сложность здесь в том, что рассматриваемая таблица является таблицей отчетов, поэтому, как только она переименовывается, а пустой ставит на место, все исторические отчеты исчезают, пока я не верну их на место. Плюс процесс слияния может быть немного болезненным из-за типа хранимых данных. В целом, это мой вероятный выбор прямо сейчас.

Мне было просто интересно, была ли у кого-то еще эта проблема раньше, и если да, то как вы справились с ней, не закрывая сайт и, надеюсь, с минимальным вмешательством пользователей? Если я выберу номер 2 или другой, похожий подход, я могу запланировать запуск контента поздно ночью и выполнить слияние рано утром следующего дня, и просто сообщить пользователям об этом заранее, так что это не так уж и сложно. Я просто смотрю, есть ли у кого-нибудь идеи для лучшего или более простого способа очистки.

Ответы [ 11 ]

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

Я думаю, что медлительность связана с «кластеризованным индексом» MySQl, где фактические записи хранятся в индексе первичного ключа - в порядке индекса первичного ключа. Это означает, что доступ к записи через первичный ключ является чрезвычайно быстрым, поскольку для него требуется только одна выборка диска, поскольку запись на диске находится там, где он нашел правильный первичный ключ в индексе.

В других базах данных без кластеризованных индексов сам индекс не содержит записи, а представляет собой просто «смещение» или «местоположение», указывающее, где находится запись в файле таблицы, а затем необходимо выполнить вторую выборку в этом файле для получения фактические данные.

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

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

...