Обработка удаления / вставки / выбора в огромной таблице
У меня есть сайт знакомств. На этом веб-сайте я ежедневно отправлял пользователю 10 совпадений с фотографиями и сохранял их в структуре как
SENDER RECEIVER
11 1
12 1
13 1
14 1
Я веду двухмесячный журнал. Пользователь также может проверить их, войдя на мой сайт.
Это означает, что есть параллельная вставка и выбор, что, конечно, не проблема.
Проблема в том, что когда пользователь становится неактивным или удаляет его идентификатор, мне нужно удалить все записи из журнала, где sender='inactive-id'.
Размер бревна составляет около 60 миллионов. Поэтому, когда запросы на удаление попадают в эту огромную таблицу, все выбранные блокируются, и мой сайт отключается.
Обратите внимание, что моя таблица - это слияние myisam, так как мне нужно хранить записи за 2-3 месяца, и 1-го числа каждого месяца я меняю определение
4 ответа
Обычно Table является наиболее детализированным объектом, заблокированным оператором DELETE. Поэтому, используя таблицу MERGE, вы объединяете несколько объектов, которые можно независимо заблокировать, в один большой объект, который будет заблокирован, когда DELETE ударит ЛЮБУЮ из его таблиц.
MERGE - это решение для таблиц, которые меняются редко или никогда: MERGE Table Преимущества и недостатки.
У вас есть 2 варианта:
Минимизировать воздействие замков:
- Удалить небольшими партиями
- Запустить удаление в часы низкой нагрузки
- Подумайте не удалять вообще, если это не сэкономит вам много места
- Вместо удаления строк пометьте их как "удаленные" или устаревшие и исключите из запросов SELECT.
Блокируйте объекты меньшего размера (вместо блокировки всех ваших таблиц одновременно):
- Иметь несколько операторов Delete для удаления из каждой из базовых таблиц
- Удалите определение MERGE, удалите данные из каждой базовой таблицы, создайте MERGE. Тем не менее, я думаю, что вы можете сделать это, не опуская определение MERGE.
- Используйте разбиение.
Цитата из руководства MySQL:
Альтернативой таблице MERGE является многораздельная таблица, в которой разделы одной таблицы хранятся в отдельных файлах. Секционирование позволяет выполнять некоторые операции более эффективно и не ограничивается механизмом хранения MyISAM. Для получения дополнительной информации см. Глава 18, Разделение.
Я настоятельно рекомендую разделять, потому что: - Вы можете полностью автоматизировать процесс ведения журнала / хранения данных: сценарий может создавать новые и удалять пустые разделы, перемещать устаревшие данные в другую таблицу и затем усекать эту таблицу. - обеспечивается уникальность ключа - блокируется только раздел, содержащий данные, подлежащие удалению. Выбирает на других разделах работает как обычно. - Поиск выполняется на всех разделах одновременно (как и в MERGE), но вы можете использовать HASH SubPartitioning для дальнейшего ускорения поиска.
Однако, если вы считаете, что преимущества разбиения будут перевешены стоимостью разработки, то, может быть, вам вообще не следует удалять эти данные?
Я думаю, что лучшим решением будет установка разделов в журнале на основе идентификатора пользователя. Таким образом, при запуске удаления Db будет заблокирован только один раздел.
Если вы воспользуетесь Google "Удалить на огромной таблице", вы получите информативные результаты. Вот первые три хита:
http://www.dba-oracle.com/t_oracle_fastest_delete_from_large_table.htm
Улучшение времени DELETE и INSERT для большой таблицы, имеющей структуру индекса
http://www.dbforums.com/microsoft-sql-server/1635228-fastest-way-delete-large-table.html
Один метод, который все они упоминают, - это удаление небольшими партиями, а не все сразу. Вы говорите, что таблица содержит данные за 2 месяца. Может быть, вы запускаете операторы удаления для каждого дня отдельно?
Надеюсь, это поможет!
Если вы используете InnoDB и создаете отношения FOREIGN KEY, вы можете автоматически удалять строки при удалении самого пользователя:
CREATE TABLE `DailyChoices`(
sender
INT (11) NOT NULL,receiver
INT (11) NOT NULL, ОГРАНИЧЕННЫЙ ИНОСТРАННЫЙ КЛЮЧ (sender
) РЕКОМЕНДАЦИИ users
(userid
) НА УДАЛИТЬ КАСКАД НА ОБНОВЛЕНИЕ КАСКАД) ТИП = InnoDB;