Как сжать / очистить файл ibdata1 в MySQL
Я использую MySQL в localhost в качестве "инструмента запросов" для выполнения статистики в R, то есть каждый раз, когда я запускаю скрипт R, я создаю новую базу данных (A), создаю новую таблицу (B), импортирую данные в B, отправьте запрос, чтобы получить то, что мне нужно, а затем я опускаю B и отбрасываю A.
У меня все работает нормально, но я понимаю, что размер файла ibdata быстро увеличивается, я ничего не хранил в MySQL, но файл ibdata1 уже превысил 100 МБ.
Я использую более или менее настройки MySQL по умолчанию для настройки, есть ли способ, которым я могу автоматически сжимать / очищать файл ibdata1 через фиксированный период времени?
10 ответов
Тот ibdata1
не уменьшается - это особенно раздражающая особенность MySQL. ibdata1
Файл не может быть сокращен, если вы не удалите все базы данных, не удалите файлы и не перезагрузите дамп.
Но вы можете настроить MySQL так, чтобы каждая таблица, включая ее индексы, сохранялась как отдельный файл. Таким образом ibdata1
не будет расти как большой. Согласно комментарию Билла Карвина, это включено по умолчанию в версии 5.6.6 MySQL.
Это было некоторое время назад, я сделал это. Однако, чтобы настроить ваш сервер на использование отдельных файлов для каждой таблицы, вам нужно изменить my.cnf
чтобы включить это:
[mysqld]
innodb_file_per_table=1
http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html
Как вы хотите вернуть пространство из ibdata1
вы на самом деле должны удалить файл:
- Сделать
mysqldump
всех баз данных, процедур, триггеров и т. д., кромеmysql
а такжеperformance_schema
базы данных - Отбросьте все базы данных, кроме двух указанных выше.
- Стоп MySQL
- удалять
ibdata1
а такжеib_log
файлы - Запустите MySQL
- Восстановить из дампа
Когда вы запускаете MySQL на шаге 5, ibdata1
а также ib_log
файлы будут воссозданы.
Теперь вы готовы идти. Когда вы создаете новую базу данных для анализа, таблицы будут расположены в отдельных ibd*
файлы, не в ibdata1
, Как вы обычно удаляете базу данных вскоре после ibd*
файлы будут удалены.
http://dev.mysql.com/doc/refman/5.1/en/drop-database.html
Вы, наверное, видели это:
http://bugs.mysql.com/bug.php?id=1341
С помощью команды ALTER TABLE <tablename> ENGINE=innodb
или же OPTIMIZE TABLE <tablename>
Можно извлекать данные и индексировать страницы из ibdata1 в отдельные файлы. Однако ibdata1 не будет уменьшаться, если вы не выполните описанные выше действия.
Учитывая information_schema
Это не нужно и не возможно отбросить. На самом деле это просто набор представлений только для чтения, а не таблиц. И нет никаких файлов, связанных с ними, даже каталог базы данных. informations_schema
использует механизм памяти db и сбрасывается и восстанавливается при остановке / перезапуске mysqld. См. https://dev.mysql.com/doc/refman/5.7/en/information-schema.html.
Добавляя к ответу Джона П,
Для системы linux шаги 1-6 могут быть выполнены с этими командами:
mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
DROP DATABASE [database_name];
sudo /etc/init.d/mysqld stop
sudo rm /var/lib/mysql/ibdata1
sudo rm /var/lib/mysql/ib_logfile
(и удалите любой другой файл ib_logfile, который может быть названib_logfile0
,ib_logfile1
так далее...)sudo /etc/init.d/mysqld start
create database [database_name];
mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql
Предупреждение: эти инструкции приведут к потере других баз данных, если у вас есть другие базы данных в этом экземпляре mysql. Убедитесь, что шаги 1,2 и 6,7 изменены, чтобы охватить все базы данных, которые вы хотите сохранить.
Когда вы удаляете таблицы innodb, MySQL не освобождает пространство внутри файла ibdata, поэтому продолжает расти. Эти файлы практически не уменьшаются.
Как уменьшить существующий файл ibdata:
http://dev.mysql.com/doc/refman/5.5/en/innodb-resize-system-tablespace.html
Вы можете написать сценарий и запланировать запуск сценария через определенный промежуток времени, но для описанной выше установки кажется, что несколько табличных пространств - более простое решение.
Если вы используете опцию конфигурации innodb_file_per_table
Вы создаете несколько табличных пространств. То есть MySQL создает отдельные файлы для каждой таблицы вместо одного общего файла. Эти отдельные файлы хранятся в каталоге базы данных, и они удаляются при удалении этой базы данных. Это должно устранить необходимость сокращения / очистки файлов ibdata в вашем случае.
Дополнительная информация о нескольких табличных пространствах:
http://dev.mysql.com/doc/refman/5.5/en/innodb-multiple-tablespaces.html
Быстро запишем процедуру принятого ответа в bash:
#!/usr/bin/env bash
DATABASES="$(mysql -e 'show databases \G' | grep "^Database" | grep -v '^Database: mysql$\|^Database: binlog$\|^Database: performance_schema\|^Database: information_schema' | sed 's/^Database: //g')"
mysqldump --databases $DATABASES -r alldatabases.sql && echo "$DATABASES" | while read -r DB; do
mysql -e "drop database \`$DB\`"
done && \
/etc/init.d/mysql stop && \
find /var/lib/mysql -maxdepth 1 -type f \( -name 'ibdata1' -or -name 'ib_logfile*' \) -delete && \
/etc/init.d/mysql start && \
mysql < alldatabases.sql && \
rm -f alldatabases.sql
Сохранить как purge_binlogs.sh
и беги как root
,
Исключает mysql
, information_schema
, performance_schema
(а также binlog
каталог).
Предполагается, что у вас есть полномочия администратора в /root/.my.cnf
и что ваша база данных живет по умолчанию /var/lib/mysql
каталог.
Вы также можете очистить двоичные журналы после запуска этого сценария, чтобы восстановить больше места на диске с помощью:
PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;
Если вы используете механизм хранения InnoDB для (некоторых) таблиц MySQL, вы, вероятно, уже столкнулись с проблемой его конфигурации по умолчанию. Как вы, возможно, заметили, в каталоге данных вашего MySQL (в Debian/Ubuntu - /var/lib/mysql) находится файл с именем 'ibdata1'. Он содержит почти все данные InnoDB (это не журнал транзакций) экземпляра MySQL и может быть довольно большим. По умолчанию этот файл имеет начальный размер 10 МБ и автоматически расширяется. К сожалению, файлы данных InnoDB не могут быть сжаты. Вот почему DELETEs, TRUNCATEs, DROPs и т. Д. Не будут освобождать пространство, используемое файлом.
Я думаю, что вы можете найти хорошее объяснение и решение там:
Кажется, никто не упоминает о влиянии
innodb_undo_log_truncate
настройка может иметь.
Прочитав сообщение в блоге Percona по этой теме, я включил в своей MariaDB 10.6 усечение
UNDO LOG
записей, которые заполнили 95% , и, после полного удаления и восстановления, с этого момента мой больше не рос.
По умолчанию
innodb_undo_log_truncate = 0
я легко достиг 10% занимаемой базы данных, то есть десятков гигабайт.
С
innodb_undo_log_truncate = 1
,
ibdata1
это фирма на 76 Мб.
Если ваша цель - следить за свободным пространством MySQL, и вы не можете остановить MySQL, чтобы сжать файл ibdata, то получите его с помощью команд состояния таблицы. Пример:
MySQL> 5.1.24:
mysqlshow --status myInnodbDatabase myTable | awk '{print $20}'
MySQL <5.1.24:
mysqlshow --status myInnodbDatabase myTable | awk '{print $35}'
Затем сравните это значение с вашим файлом ibdata:
du -b ibdata1
Источник: http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html
В новой версии mysql-сервера приведенные выше рецепты сокрушат базу "mysql". В старой версии это работает. В некоторых новых таблицах происходит переключение на тип таблицы INNODB, и таким образом вы повредите их. Самый простой способ - сбросить все ваши базы данных, удалить mysql-сервер, добавить в оставшийся my.cnf:
[mysqld]
innodb_file_per_table=1
erase all in /var/lib/mysql
install mysql-server
restore users and databases
Недавно мы столкнулись с ошибкой в MariaDB 10.6.13 (исправленной в 10.6.14), из-за которой наш файл увеличивался на 5+ ГБ/день. К тому времени, когда начали рассылаться оповещения об использовании дискового пространства, размер файла превысил 400 ГБ.
Общий объем наших баз данных составляет около 865 ГБ, поэтому логическое резервное копирование/восстановление осуществляется с помощью
Вот некоторые примечания/процедуры, которым я следовал, когда перестраивал наши серверы БД, чтобы вернуться к разумному размеру:
я использую
уже. Я использовал этот инструмент , чтобы определить использование пространства на страницах журнала отмены (это заняло несколько часов, это было до того, как я узнал об ошибке в 10.6.13 и не знал наверняка, что вызывает такой рост). много).
У нас есть одна первичная и три реплики.
Сначала я снял одну реплику с производства, использовал ее для дампа/восстановления, а затем сделал резервную копию восстановленной реплики. Я использовал эту резервную копию для восстановления остальных серверов БД (что намного быстрее).
У нас уже есть процедура полного резервного копирования с использованием . Прежде чем что-либо делать, убедитесь, что у вас есть заведомо исправная полная резервная копия!
Восстановление первого сервера
Остановить все записи в базу данных.
Я делаю
Использовать
#!/usr/bin/bash
time mydumper -t "$(nproc)" \
--compress \
--triggers \
--routines \
--events \
--rows 10000000 \
--verbose 3 \
--build-empty-files \
--regex '^(?!(test|performance_schema|information_schema|sys))' \
--logfile /mnt/mysql_backups/ibdatafix_backup.log \
--outputdir /mnt/mysql_backups/ibdatafix_backup 2>&1
echo "DUMP ON $(hostname) DONE" | mail -s "DUMP ON $(hostname) DONE" root
Создание дампа БД объемом 865 ГБ на довольно мощном корпоративном сервере с 4 твердотельными накопителями в аппаратном RAID 10 заняло 12 минут. На старом сервере это занимает менее одного часа.
Проверьте журнал на наличие ошибок.
Я попробовал просто удалить наши базы данных, закрыть MariaDB и удалить, но это вызвало проблемы, поэтому я закрыл MariaDB и стер весь каталог данных (
Затем я добавил эту конфигурацию, чтобы переместить журналы отмены из . Конечно, если вы хотите это сделать, приспособьтесь к вашей среде. На данный момент я думаю, что это хорошая идея, главным образом потому, что нет возможности усечь, и я не хочу в ближайшее время снова перестраивать все наши серверы.
# About 3GB.
innodb_max_undo_log_size = 3221225472
# I moved the undo logs into a separate volume. You can set this to
# /var/lib/mysql.
innodb_undo_directory = /var/lib/mysql_undo_logs
# This appears to only work if innodb_undo_directory is set and
# the undo logs are separate from ibdata1.
innodb_undo_log_truncate = 1
innodb_undo_tablespaces = 3
Временно добавьте их в конфигурацию для восстановления:
innodb_flush_log_at_trx_commit=0
net_read_timeout=60
performance_schema=off
innodb_adaptive_hash_index=off
sql_mode=NO_ENGINE_SUBSTITUTION
innodb_doublewrite=off
slow_query_log = 0
Теперь запустите MySQL/MariaDB и восстановите:
#!/usr/bin/bash
time myloader \
--compress-protocol \
--directory /mnt/mysql_backups/ibdatafix_backup \
--overwrite-tables \
--queries-per-transaction 1000 \
# The recommendation here is half of your available cores. I set this
# too high and it lead to timeouts and a botched restore.
--threads 4 \
--verbose 3 > restore.log 2>&1
echo "RESTORE ON $(hostname) DONE" | mail -s "RESTORE ON $(hostname) DONE" root
На это ушло около 12 часов.
Обязательно проверьте
Удалите временную конфигурацию и перезапустите MySQL/MariaDB.
Прежде чем сделать что-нибудь еще, я побежал
Если вам нужно перестроить другие серверы (другие реплики/основные), вы можете использовать
# On the freshly rebuilt server:
rm -rf /mnt/mysql_backups/ibdatafix_backup/*
mariabackup --defaults-file=/etc/mysql/my.cnf --parallel=4 \
--compress --compress-threads=4 --safe-slave-backup --slave-info \
--user=root --backup --target-dir=/mnt/mysql_backups/ibdatafix_backup
# Then on the other server(s), shut down the DB, wipe /var/lib/mysql, and copy the backup back over:
systemctl stop mariadb/mysql
cd /var/lib/mysql
rm -rf *
# This is an NFS share mounted on all DB servers.
rsync -av /mnt/mysql_backups/ibdatafix_backup .
mariabackup --decompress --parallel=8 --remove-original --target-dir=.
mariabackup --prepare --use-memory=32G --target-dir=.
chown -R mysql:mysql .
systemctl start mariadb/mysql
# Set up replication etc.
Все это заняло около двух часов на каждый сервер (865 ГБ в базах данных, корпоративных серверах, 10-гигабайтной сети, 4 твердотельных накопителя в RAID 10).
Усечение журнала отмены теперь определенно работает. я установил
Как уже отмечалось, вы не можете сжать ibdata1 (для этого вам нужно создать дамп и перестроить), но в этом часто нет необходимости.
Используя автоэкстенд (вероятно, самый распространенный параметр размера), ibdata1 предварительно выделяет хранилище, увеличиваясь при каждом его заполнении. Это делает запись быстрее, так как пространство уже выделено.
Когда вы удаляете данные, они не уменьшаются, но пространство внутри файла помечается как неиспользуемое. Теперь, когда вы вставляете новые данные, они будут повторно использовать пустое пространство в файле, прежде чем расширять его.
Так что он будет только расти, если вам действительно нужны эти данные. Если вам не нужно пространство для другого приложения, вероятно, нет причин его уменьшать.