Я вирішив це в StackOverflow ще в жовтні 2010 року .
Майте на увазі найзайнятіший файл в інфраструктурі InnoDB: / var / lib / mysql / ibdata1
Цей файл зазвичай містить чотири типи інформації
- Дані таблиці
- Табличні покажчики
- Дані MVCC (мультивалюючий контроль за сумісністю)
- Метадані таблиці (Список ідентифікаторів простору таблиць)
Запуск OPTIMIZE TABLE
проти таблиці InnoDB, що зберігається в ibdata1, робить дві речі:
- Робить дані таблиці та індекси суміжними всередині ibdata1, тим самим швидше отримуючи доступ
- Це змушує ibdata1 рости, оскільки суміжні сторінки даних та покажчики додаються до ibdata1
Хоча ви можете відокремлювати дані таблиці та індекси таблиць від ibdata1 та керувати ними самостійно, використовуючи innodb_file_per_table , велика розбіжна ціла дискова область в ibdata1 просто не вийде з ладу і не може бути відновлена. Ви повинні зробити більше.
Щоб скоротити ibdata1 раз і назавжди, ви повинні зробити наступне:
1) MySQLDзавантажте всі бази даних у текстовий файл SQL (назвіть це /root/SQLData.sql)
2) Відкинути всі бази даних (крім схеми mysql)
3) Вимкнення mysql
4) Додайте наступні рядки до /etc/my.cnf
[mysqld]
innodb_file_per_table
innodb_flush_method=O_DIRECT
innodb_log_file_size=1G
innodb_buffer_pool_size=4G
Сторінка: Незалежно від вашого набору для innodb_buffer_pool_size, переконайтесь, що innodb_log_file_size становить 25% від innodb_buffer_pool_size.
5) Видаліть ibdata1, ib_logfile0 та ib_logfile1
На цьому етапі має бути лише схема mysql в / var / lib / mysql
6) Перезапустіть mysql
Це відтворить ibdata1 у 10 або 18 МБ (залежно від версії MySQL), ib_logfile0 та ib_logfile1 на 1G кожен
7) Перезавантажте /root/SQLData.sql в mysql
ibdata1 зростатиме, але містить лише метадані таблиці. Насправді він росте дуже повільно з роками. Єдиний спосіб швидкого зростання ibdata1 - це якщо у вас є одне або більше з наступного:
- Багато DDL (
CREATE TABLE
, DROP TABLE
, ALTER TABLE
)
- Дуже багато угод
- Багато змін, які потрібно здійснити за кожну транзакцію
Кожна таблиця InnoDB буде існувати поза ibdata1
Припустимо, у вас є таблиця InnoDB під назвою mydb.mytable. Якщо зайти в / var / lib / mysql / mydb, ви побачите два файли, що представляють таблицю
- mytable.frm (Заголовок двигуна зберігання)
- mytable.ibd (Домашні дані таблиці та індекси таблиць для mydb.mytable)
ibdata1 більше ніколи не буде містити дані InnoDB та індекси.
За допомогою параметра innodb_file_per_table в /etc/my.cnf ви можете запустити OPTIMIZE TABLE mydb.mytable;
і файл /var/lib/mysql/mydb/mytable.ibd фактично скоротиться.
Я робив це багато разів у своїй кар'єрі як MySQL DBA
Насправді, коли я це зробив, я згорнув файл ibdata1 об'ємом 50 ГБ на 500 Мб.
Спробувати. Якщо у вас є додаткові запитання з цього приводу, напишіть мені. Довірся мені. Це спрацює в короткостроковій перспективі і в довгостроковій перспективі !!!
ОНОВЛЕННЯ 2012-04-19 09:23 EDT
Після виконання вищезазначених кроків, як можна визначити, які таблиці потрібно дефрагментацію? Це можна дізнатися, але у вас буде сценарій.
Ось приклад: припустимо, у вас є таблиця mydb.mytable
. Якщо ввімкнено innodb_file_per_table, у вас є файл /var/lib/mysql/mydb/mytable.ibd
Вам доведеться отримати два числа
ФАЛІЗАЦІЯ З ОС: Ви можете встановити розмір файлів в ОС таким чином
ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'
ФАЛІЗАЦІЯ З ІНФОРМАЦІЇ_ШЕМИ: Ви можете встановити розмір файлів з інформаційних таблиць, таких як:
SELECT (data_length+index_length) tblsize FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Просто відніміть значення INFORMATION_SCHEMA від значення ОС і розділіть різницю на значення INFORMATION_SCHEMA.
Звідти ви вирішите, який відсоток вважаєте за потрібне дефрагментувати цю таблицю. Звичайно, ви дефрагментуєте його за допомогою однієї з наступних команд:
OPTIMIZE TABLE mydb.mytable;
або
ALTER TABLE mydb.mytable ENGINE=InnoDB;