вторник, 29 декабря 2015 г.

Быстрое удаление из больших таблиц MySQL

Если требуется удалить большие объёмы данных из таблиц MySQL, это занимает слишком много времени.

Ускорить процесс может такая процедура.

# Пример использования процедуры:
# CALL cut_table('my_cool_table');


DROP PROCEDURE IF EXISTS cut_table;

DELIMITER //
CREATE PROCEDURE cut_table(IN tableName CHAR(255))
BEGIN

SET @tableName = tableName;
SET @tableNameOld = CONCAT(@tableName, '_old');
SET @tableNameCopy = CONCAT(@tableName, '_copy');

# Количество строк, которые мы оставляем в начале и конце таблицы.
SET @skipCount = 10000;

# Считаем общее количество строк в таблице.
SET @sql_text = CONCAT('SELECT count(*) INTO @totalRows FROM ', @tableName);

PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SELECT @totalRows;

SET @minRows = @skipCount*2;

# Если строк мало, то не обрезаем таблицу.
# Эта проверка спасает нас, если мы вызовем скрипт дважды для одной таблицы.
IF (@totalRows <= @minRows) THEN 
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Table has too few rows. No need to suck it.';
END IF;

# Создаём структурную копию таблицы.
# Внешние ключи не копируются, их требуется задать отдельно.
SET @sql_text = CONCAT('CREATE TABLE ', @tableNameCopy, ' LIKE ', @tableName);

PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

# Копируем те данные, которые нам нужны.
SET @sql_text = CONCAT('INSERT INTO ', @tableNameCopy, ' SELECT * FROM ', @tableName, ' ORDER BY id ASC LIMIT ?');

PREPARE stmt FROM @sql_text;
EXECUTE stmt USING @skipCount;
DEALLOCATE PREPARE stmt;


SET @sql_text = CONCAT('INSERT INTO ', @tableNameCopy, ' SELECT * FROM ', @tableName, ' ORDER BY id DESC LIMIT ?');

PREPARE stmt FROM @sql_text;
EXECUTE stmt USING @skipCount;
DEALLOCATE PREPARE stmt;

# Переименовываем таблицы, замещая старую таблицу новой.
SET @sql_text = CONCAT('RENAME TABLE ', @tableName, ' TO ', @tableNameOld, ', ', @tableNameCopy, ' TO ', @tableName);

PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

# Удаляем старую таблицу.
SET @sql_text = CONCAT('DROP TABLE ', @tableNameOld);

PREPARE stmt FROM @sql_text;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;


END //
DELIMITER ;