Борьба с разросшимся ibdata1 файлом MySQL

Борьба с разросшимся ibdata1 файлом MySQL

Случилась недавно проблемка. Получил уведомление о том, что на рабочем сервере заканчивается свободное место. Был слегка удивлен, ведь на нем хостились всего лишь тестовые версии сайтов, для демонстрации клиентам.

Начал разбираться что происходит. Первая идея — кто то, снова, нашел дыру и пытается спамить. Такое уже бывало. Рабочие папки exim (по моему) росли в размере с невероятной скоростью, пока последний не был отключен.
Теория не подтвердилась.

Пришлось локализовать «распухшее» место программой du:

# ищем переростка в корне директории больше 200 Мб
$ du -sh /*  --threshold=200M | sort -h

# ищем в следующей самой жирной директории, например
$ du -sh /var/*  --threshold=200M | sort -h

# ... и так далее, пока не локализуем виновника

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

Пошел смотреть какая база разрослась. Все оказалось просто — я не отключил один старый сайт на Magento CMS. Она собирала информацию о пользователях и их устройствах, переходах, действиях и чёрт знает что еще. И, внимание, хранила все это она в БД.
Не поверите, на «мертвом» сайте за 5+ лет побывало то ли 7, то ли 8 тыс человек. Которые сгенерировали по 14 000 000 (четырнадцать миллионов) записей в двух таблицах.
Порядка 7 Gb логов всего в двух табличках!

Данные эти мне не нужны, поэтому TRUNCATE и дело с концом.

И вот тут меня ждал очень неприятный сюрприз — размер файла ibdata1 не уменьшился вообще.
ALTER TABLE <...> ENGINE=innodb не помогло. OPTIMIZE TABLE <...> — тоже.

Решение

Нашел решние на Stackoverflow.
Оказалось, что это, типа, так и должно быть. Файл можно уменьшить только удалив ibdata1 и ib_log.

1. Делаем дамп базы

Надо учесть, что базы mysql и performance_schema мы удалять не будем.
Самый простой способ, если баз не так много:

$ mysqldump  -uroot -proot --databases db_name1 [db_name2 db_name3...] > dump.sql

Если баз много, то можно воспользоваться такой конструкцией:

$ echo 'show databases;' | mysql -uroot -proot | grep -v ^mysql$ | grep -v ^performance_schema$ | xargs mysqldump -uroot -proot  --databases > dump.sql

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

# 1. получаем список всех таблиц в файл
$ echo 'show databases;' | mysql -uroot -proot > dblist.txt
# 2. удалить из этого файлика все ненужные таблицы
# 3. Сделать дамп
$ cat dblist.txt | xargs mysqldump -uroot -proot --databases > dump.sql

2. Удаляем все базы данных.

КРОМЕ mysql и performance_schema

$ mysql -uroot -proot
mysql > DROP DATABASE db_name1;
mysql > DROP DATABASE db_name2;
...
mysql > DROP DATABASE db_nameN;
Важно из справки по DROP DATABASE

Оператор DROP DATABASE удаляет все таблицы в указанной базе данных и саму базу. Если вы выполняете DROP DATABASE на базе данных, символически связанной с другой, то удаляется как ссылка, так и оригинальная база данных. Будьте ОЧЕНЬ внимательны при работе с этой командой!

3. Тормозим mysql

Ubuntu:

$ sudo service mysqld stop
## или
$ sudo service mysql stop

CentOS 7

$ sudo systemctl stop mysql

4. Исправляем конфиг my.cnf

Данный файл лежит, скорее всего, где то тут: /etc/mysql/my.cnf.
Чтобы найти все места откуда забирается конфиг, можно выполнить следующую команду:

$ mysql --help

По идее, вы должны будете увидеть нечто подобное (строки 8-9):

$ mysql --help

mysql  Ver 15.1 Distrib 10.3.20-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Usage: mysql [OPTIONS] [database]

Default options are read from the following files in the given order: 
/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf
...
...

После того, как нашли конфиг, в него нужно найти секцию [mysqld] и добавить (или исправить, если есть) значение параметра:

innodb_file_per_table=1

5. Удаляем файлы ibdata1 и ib_log

6. Стартуем mysql

Ubuntu:

$ sudo service mysqld start
## или
$ sudo service mysql start

CentOS 7

$ sudo systemctl start mysql

7. Восстанавливаем дамп

$ mysql -uroot -proot < dump.sql

Profit

Комментарии ()