Как сжать / очистить файл ibdata1 в MySQL


561

Я использую MySQL в localhost в качестве «инструмента запросов» для выполнения статистики в R, то есть каждый раз, когда я запускаю скрипт R, я создаю новую базу данных (A), создаю новую таблицу (B), импортирую данные в B , отправьте запрос, чтобы получить то, что мне нужно, а затем я опускаю B и отбрасываю A.

Это нормально работает для меня, но я понимаю, что размер файла ibdata быстро увеличивается, я ничего не хранил в MySQL, но файл ibdata1 уже превысил 100 МБ.

Я использую более или менее настройку MySQL по умолчанию для установки, есть ли способ, которым я могу автоматически сжимать / очищать файл ibdata1 через фиксированный период времени?


Ответы:


778

Это 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вы должны удалить файл:

  1. Выполните mysqldumpвсе базы данных, процедуры, триггера и т.д. , за исключением mysqlи performance_schemaбаз данных
  2. Отбросьте все базы данных, кроме двух указанных выше.
  3. Стоп MySQL
  4. Удалить ibdata1и ib_logфайлы
  5. Запустите MySQL
  6. Восстановить из дампа

При запуске 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-двигатель и отбрасываются и регенерируют после остановки / перезапуска туздЫ. См. Https://dev.mysql.com/doc/refman/5.7/en/information-schema.html .


16
@JordanMagnuson Не утруждайте себя информацией. На самом деле это просто набор представлений только для чтения, а не таблиц. И нет никаких файлов, связанных с ними. Там даже нет каталога для базы данных. Informations_schema использует механизм памяти db и удаляется и восстанавливается при остановке / перезапуске mysqld. См. Dev.mysql.com/doc/refman/5.5/en/information-schema.html . Что касается performance_schema, я сам не использовал эту схему.
Джон П

4
Я не знаю, является ли это недавним событием, но как только опция innodb_file_per_table включена, вы можете просто запустить «ALTER TABLE <tablename> ENGINE = InnoDB» (даже если это уже InnoDB), и она переместит таблицу в отдельный файл , Не нужно сбрасывать базы данных и тому подобное.
кр.

3
+1 FWIW, MySQL 5.6 включен innodb_file_per_tableпо умолчанию.
Билл Карвин

3
Да, ожидается, что ibdata1 будет присутствовать вместе с другими файлами. Файл ibdata1 по-прежнему будет содержать метаданные о таблицах, журнале отмены и буферах.
Джон П

1
На моем сервере не хватает места из-за файла ibdata1, поэтому я не могу даже вывести базы данных. Будет ли то же самое просто переместить файлы в / var / lib / mysql (кроме «mysql», «ibdata1», «ib_logfile0» и «ib_logfile1»), а затем выполнить шаги? См stackoverflow.com/questions/2482491/...
Sophivorus

47

Добавляя к ответу Джона П ,

Для системы linux шаги 1-6 могут быть выполнены с этими командами:

  1. mysqldump -u [username] -p[root_password] [database_name] > dumpfilename.sql
  2. DROP DATABASE [database_name];
  3. sudo /etc/init.d/mysqld stop
  4. sudo rm /var/lib/mysql/ibdata1
    sudo rm /var/lib/mysql/ib_logfile (и удалите любой другой файл ib_logfile, который может быть назван ib_logfile0и ib_logfile1т. д.)
  5. sudo /etc/init.d/mysqld start
  6. create database [database_name];
  7. mysql -u [username]-p[root_password] [database_name] < dumpfilename.sql

Предупреждение: эти инструкции приведут к потере других баз данных, если у вас есть другие базы данных в этом экземпляре mysql. Убедитесь, что шаги 1,2 и 6,7 изменены, чтобы охватить все базы данных, которые вы хотите сохранить.


6
Вам нужно повторить 1,2 и 6 для каждой базы данных, в которой есть таблицы InnoDB.
маркиз Лорн

4
Вам нужно еще пару шагов между № 5 и № 6. Вы должны воссоздать базу данных и переназначить разрешения. Так из командной строки клиента mysql, create database database_name;а затемgrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
Фред

1
@fred Мне не нужно было предоставлять привилегии при этом. Возможно, потому что я воссоздал базу данных с тем же именем?
crmpicco 24.12.15

2
Чтобы ввести пароль в Password:командной строке (что является более безопасной практикой), просто введите -pбез действительного пароля.
ADTC

Триггеры, события и подпрограммы / функции не сбрасываются, если вы не укажете mysqldump сделать это. Добавьте также --triggers, --events и --routines, если они есть в любой из ваших баз данных. Кроме того, просто сделайте дамп с --all-database, чтобы сбросить все базы данных одновременно, а не одну за другой.
Friek

34

Когда вы удаляете таблицы 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


сломана первая ссылка, наиболее близкое совпадение, которое я смог найти: dev.mysql.com/doc/refman/5.5/en/…
BlackICE

14

Если вы используете механизм хранения InnoDB для (некоторых) таблиц MySQL, вы, вероятно, уже столкнулись с проблемой его конфигурации по умолчанию. Как вы, наверное, заметили, в каталоге данных вашего MySQL (в Debian / Ubuntu - / var / lib / mysql) находится файл с именем 'ibdata1'. Он содержит почти все данные InnoDB (это не журнал транзакций) экземпляра MySQL и может стать довольно большим. По умолчанию этот файл имеет начальный размер 10 МБ и автоматически расширяется. К сожалению, файлы данных InnoDB не могут быть сжаты. Вот почему DELETEs, TRUNCATEs, DROPs и т. Д. Не будут освобождать пространство, используемое файлом.

Я думаю, что вы можете найти хорошее объяснение и решение там:

http://vdachev.net/2007/02/22/mysql-reducing-ibdata1/


11

Быстро запишем процедуру принятого ответа в 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_schemabinlogкаталог).

Предполагается, что у вас есть полномочия администратора /root/.my.cnfи ваша база данных находится в /var/lib/mysqlкаталоге по умолчанию .

Вы также можете очистить двоичные журналы после запуска этого сценария, чтобы восстановить больше места на диске с помощью:

PURGE BINARY LOGS BEFORE CURRENT_TIMESTAMP;

До сих пор не уверен, почему, но сегодня некоторые из моих таблиц InnoDB были повреждены во время аналогичного процесса, поэтому я не буду удалять alldatabases.sqlперед двойной проверкой, если все таблицы исправны. Что касается некоторых улучшений: установите innodb_fast_shutdown=0перед выключением, установите autocommit=0перед импортом файла SQL, выполните COMMITи установите autocommit=1после импорта файла SQL, используйте mysqlcheck --all-databasesперед удалением резервной копии.
Виктор

6

Если ваша цель - следить за свободным пространством 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


4

В новой версии MySQL-сервера приведенные выше рецепты сокрушат базу «MySQL». В старой версии это работает. В некоторых новых таблицах переключается на тип таблицы INNODB, и таким образом вы повредите их. Самый простой способ:

  • сбросить все ваши базы данных
  • удалить MySQL-сервер,
  • добавьте в оставшийся my.cnf:
    [mysqld]
    innodb_file_per_table=1
  • стереть все в / var / lib / mysql
  • установить mysql-сервер
  • восстановить пользователей и базы данных

1

Как уже отмечалось, вы не можете сжать ibdata1 (для этого вам нужно создать дамп и пересобрать), но в этом также нет особой необходимости.

Используя автоматическое расширение (вероятно, самый распространенный параметр размера), ibdata1 предварительно выделяет хранилище, увеличиваясь при каждом его заполнении. Это делает запись быстрее, так как пространство уже выделено.

Когда вы удаляете данные, они не уменьшаются, но пространство внутри файла помечается как неиспользуемое. Теперь, когда вы вставляете новые данные, они будут повторно использовать пустое пространство в файле перед дальнейшим расширением файла.

Так что он будет только расти, если вам действительно нужны эти данные. Если вам не нужно пространство для другого приложения, вероятно, нет причин его уменьшать.


66
Я думаю, что вы слишком пренебрежительно относитесь к необходимости освободить пространство.
drewish

2
У меня есть твердотельный раздел 60Gig. У меня быстро заканчивается свободное место, так как я работаю с базами данных 4+ гигов. Я надеюсь переместить mysql в другой раздел в ближайшее время, но этот вопрос и ответы на него помогут мне в это время
NullVoxPopuli

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

1
У меня есть файл 500G ibdata1 - но почти все данные, которые были в нем хранятся, теперь хранятся в файлах для каждой базы данных. Мне очень нужно сократить эту колоссальную трата пространства!
Франк

2
Полная чушь! Файл, который продолжает увеличиваться в размерах, должен быть обрезан независимо от того, заканчивается ли у вас свободное место или нет . Я бы назвал это storage leak.
ADTC
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.