Як зменшити / очистити файл ibdata1 у MySQL


561

Я використовую MySQL у localhost як "інструмент запиту" для статистики R, тобто кожен раз, коли я запускаю скрипт R, я створюю нову базу даних (A), створюю нову таблицю (B), імпортую дані в B , надішліть запит, щоб отримати те, що мені потрібно, і тоді я кидаю B і краплю A.

Для мене це працює добре, але я розумію, що розмір файлу ibdata швидко збільшується, я нічого не зберігав у MySQL, але файл ibdata1 вже перевищував 100 Мб.

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


Відповіді:


777

Це 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/uk/innodb-multiple-tablespaces.html

Оскільки ви хочете повернути простір, ibdata1вам потрібно видалити файл:

  1. Виконайте mysqldumpвсі бази даних, процедури, тригера і т.д. , за винятком mysqlі performance_schemaбаз даних
  2. Відкиньте всі бази, крім вищевказаних 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-двигун пам'яті і скидається та регенерується при зупинці / перезапуску mysqld. Дивіться https://dev.mysql.com/doc/refman/5.7/uk/information-schema.html .


16
@JordanMagnuson Не турбуйтеся кидати інформацію_schema. Це насправді лише купа переглядів лише для читання, а не таблиць. І файлів, пов’язаних з ними, немає. Не існує навіть каталогу для бази даних. Інформація_схема використовує db-двигун пам'яті і скидається та регенерується при зупинці / перезапуску mysqld. Дивіться dev.mysql.com/doc/refman/5.5/uk/information-schema.html . Щодо performance_schema, я ще не використовував цю схему.
Джон Р

4
Я не знаю, чи це нещодавня річ, але після того, як включена опція innodb_file_per_table, ви можете просто запустити "ALTER TABLE <ім'я таблиці> ENGINE = InnoDB" (навіть якщо це вже InnoDB), і він перемістить таблицю в її окремий файл . Не потрібно скидати бази даних тощо.
CR.

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 client, create database database_name;а потімgrant all privileges on database_name.* to 'username'@'localhost' identified by 'password';
fred

1
@fred Мені не потрібно було надавати пільги при цьому. Можливо, тому, що я відтворив базу даних з такою ж назвою?
crmpicco

2
Для введення пароля Password:підказки (що є більш безпечною практикою), просто поставте -pбез фактичного пароля.
ADTC

Тригери, події та процедури / функції не скидаються, якщо ви не скажете mysqldump зробити це. Додайте також --тригери, --венти та --програми, якщо будь-які ваші бази даних містять їх. Крім того, просто скиньте з --all-бази даних, щоб скинути всі бази даних відразу, а не одну за одною.
Фрік

34

Коли ви видаляєте таблиці innodb, MySQL не звільняє простір всередині файлу ibdata, тому він постійно зростає. Ці файли майже ніколи не стискаються.

Як зменшити існуючий файл ibdata:

http://dev.mysql.com/doc/refman/5.5/uk/innodb-resize-system-tablespace.html

Ви можете розписати це та запланувати виконання сценарію через певний проміжок часу, але для описаних вище параметрів здається, що декілька таблиць простору є більш простим рішенням.

Якщо ви використовуєте параметр конфігурації innodb_file_per_table , ви створюєте кілька таблиць. Тобто MySQL створює окремі файли для кожної таблиці замість одного спільного файла. Ці окремі файли зберігаються в каталозі бази даних, і вони видаляються при видаленні цієї бази даних. Це повинно усунути необхідність скорочення / очищення файлів ibdata у вашому випадку.

Додаткові відомості про декілька таблиць:

http://dev.mysql.com/doc/refman/5.5/uk/innodb-multiple-tablespaces.html


перше посилання розірвано, найближчий збіг я міг знайти: dev.mysql.com/doc/refman/5.5/uk/…
BlackICE

14

Якщо ви використовуєте механізм зберігання InnoDB для (деяких) таблиць MySQL, ви, мабуть, вже зіткнулися з проблемою з його конфігурацією за замовчуванням. Як ви, можливо, помітили, у вашому каталозі даних MySQL (у Debian / Ubuntu - / var / lib / mysql) лежить файл під назвою 'ibdata1'. Він містить майже всі дані InnoDB (це не журнал транзакцій) екземпляра MySQL і може отримати досить великий розмір. За замовчуванням цей файл має початковий розмір 10Mb і він автоматично розширюється. На жаль, дизайн даних InnoDB файлів даних не може бути скороченим. Ось чому DELETE, TRUNCATE, 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/uk/show-table-status.html


4

У новій версії рецептів mysql-сервера вище буде розбита база даних "mysql". У старій версії він працює. У нових таблицях переходить на тип типу INNODB, і тим самим ви пошкодите їх. Найпростіший спосіб - це:

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

1

Як уже зазначалося, ви не можете зменшити ibdata1 (для цього вам потрібно скинути і відновлювати), але часто також немає реальної потреби.

Використовуючи функцію autoextend (мабуть, найпоширеніший параметр розміру) ibdata1 попередньо розміщує сховище, щоразу збільшуючи його майже повний. Це робить записи швидшими, оскільки простір вже виділено.

Коли ви видаляєте дані, вони не скорочуються, але простір у файлі позначається як невикористаний. Тепер, коли ви вставляєте нові дані, він повторно використовувати порожній простір у файлі, перш ніж продовжувати рости файл.

Таким чином, він буде продовжувати зростати, лише якщо вам справді потрібні ці дані. Якщо ви дійсно не потребуєте місця для іншої програми, ймовірно, немає причин зменшувати її.


66
Думаю, ти занадто зневажливий до необхідності звільняти місце.
весело

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

3
Дякую за цю відповідь, це дуже корисно. Я очистив деякі таблиці із застарілих даних ... добре знати, що розмір диска не скоро зросте знову.
Бред

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

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