Итак, у меня есть эта таблица аудита (отслеживает действия над любой таблицей в моей базе данных):
CREATE TABLE `track_table` (
`id` int(16) unsigned NOT NULL,
`userID` smallint(16) unsigned NOT NULL,
`tableName` varchar(255) NOT NULL DEFAULT '',
`tupleID` int(16) unsigned NOT NULL,
`date_insert` datetime NOT NULL,
`action` char(12) NOT NULL DEFAULT '',
`className` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `userID` (`userID`),
KEY `tableID` (`tableName`,`tupleID`,`date_insert`),
KEY `actionDate` (`action`,`date_insert`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
и мне нужно начать архивирование устаревших предметов. Таблица выросла примерно до 50 миллионов строк, поэтому самым быстрым способом, которым я мог удалить строки, было удаление таблицы за раз (на основе tableName
).
Это работает довольно хорошо, но на некоторых таблицах с интенсивной записью это не завершится. Мой запрос удаляет все элементы, с которыми связано delete
действие в комбинации tupleID / tableName:
DELETE FROM track_table WHERE tableName='someTable' AND tupleID IN (
SELECT DISTINCT tupleID FROM track_table
WHERE tableName='someTable' AND action='DELETE' AND date_insert < DATE_SUB(CURDATE(), INTERVAL 30 day)
)
Я позволил этому запускаться на моем сервере в течение 3 дней, и он никогда не завершался для самой большой таблицы. Вывод объяснения (если я переключаю удаление, чтобы выбрать:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | PRIMARY | track_table | ref | tableID | tableID | 257 | const | 3941832 | Using where |
| 2 | DEPENDENT SUBQUERY | track_table | ref | tableID,actionDate | tableID | 261 | const,func | 1 | Using where; Using temporary |
Поэтому 4 миллиона строк не должны занимать 3 дня, я бы подумал. Мой innodb_buffer_pool_size имеет значение 3 ГБ, а сервер не настроен на использование one_file_per_table. Какие еще способы можно улучшить производительность удаления InnoDB? (Запуск MySQL 5.1.43 на Mac OSX)
источник
Удаление ненужных строк в пакете должно поддерживать работоспособность других операций. Но при удалении операции есть условия, поэтому убедитесь, что для столбцов имеется соответствующий индекс над условиями.
Поскольку MySQL не поддерживает полную функцию рыхлой сканировании индекса, вы можете попытаться настроить последовательность для
KEY actionDate (action, date_insert)
кKEY actionDate (date_insert, action)
. С префиксом date_insert MySQL должен использовать этот индекс для сканирования строк, которые предшествуют вашему состоянию datetime.С таким индексом вы можете написать SQL как:
источник
Кулак, из вашего объяснения key_len такой большой => вам нужно уменьшить размер как можно меньше. Я думаю, что для вашего запроса лучше всего изменить поле данных типа действия с char (12) на tinyint, поэтому отображение данных выглядит следующим образом:
и вы можете изменить table_id вместо tablename тоже. DDL для лучшей производительности может:
поэтому запрос может выглядеть так:
Но самым быстрым способом было использование раздела. так что вы можете удалить раздел. В настоящее время моя таблица содержит более 40 миллионов строк. и обновлять ежечасно (400 000 строк обновляются каждый раз), и я могу удалить раздел curr_date и перезагрузить данные в таблицу. команда сброса очень быстро (<100 мс). Надеюсь, это поможет.
источник