Как удалить фрагментацию из таблиц InnoDB?

13

У меня есть база данных с количеством таблиц.

Я хочу удалить некоторые записи из таблиц, например, нет записей больше 20К или 50К.

Все таблицы являются InnoDB. И file_per_tableэто прочь .

Когда я буду удалять записи из ряда таблиц, в таблицах будет фрагментация.

Есть ли способ убрать фрагментацию.?

Обновление 17 апреля

mysql> select TABLE_NAME, TABLE_SCHEMA, Data_free from information_schema.TABLES where TABLE_SCHEMA NOT IN ('information_schema', 'mysql') and Data_Free >0;
+-----------------+--------------+-----------+
| TABLE_NAME      | TABLE_SCHEMA | Data_free |
+-----------------+--------------+-----------+
| City            | world_innodb |   5242880 |
| City_Copy       | world_innodb |   5242880 |
| Country         | world_innodb |   5242880 |
| CountryLanguage | world_innodb |   5242880 |
| a               | world_innodb |   5242880 |
| t1              | world_innodb |   5242880 |
| t2              | world_innodb |   5242880 |
+-----------------+--------------+-----------+
7 rows in set (0.00 sec)

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

Абдул Манаф
источник
1
И статья InnoDB: следите за фрагментацией на блог-сайте Percona.
ypercubeᵀᴹ

Ответы:

14

Я обратился к этому в StackOverflow еще в октябре 2010 года .

Помните о самом загруженном файле в инфраструктуре InnoDB: / var / lib / mysql / ibdata1

Этот файл обычно содержит четыре типа информации

  • Данные таблицы
  • Табличные индексы
  • Данные MVCC (Multiversioning Concurrency Control)
  • Метаданные таблицы (список идентификаторов табличного пространства)

Запуск OPTIMIZE TABLEтаблицы InnoDB, хранящейся в ibdata1, делает две вещи:

  • Делает данные таблицы и индексы смежными внутри ibdata1, таким образом, более быстрый доступ
  • Это делает ibdata1 растущим, потому что смежные страницы данных и индексов добавляются к ibdata1

Хотя вы можете отделить Табличные данные и Табличные индексы от ibdata1 и управлять ими независимо, используя innodb_file_per_table , большое свободное пространство на диске в ibdata1 просто не исчезнет и не может быть восстановлено. Вы должны сделать больше.

Чтобы сжать ibdata1 раз и навсегда, вы должны сделать следующее:

1) MySQLDump все базы данных в текстовый файл 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

Фактически, в первый раз, когда я сделал это, я свернул файл ibdata1 размером 50 ГБ в 500 МБ.

Попробуйте. Если у вас есть дополнительные вопросы по этому поводу, напишите мне. Доверьтесь мне. Это будет работать в краткосрочной и долгосрочной перспективе !!!

ОБНОВЛЕНИЕ 2012-04-19 09:23 ПО ВОСТОЧНОМУ ВРЕМЕНИ

После выполнения описанных выше шагов, как вы можете определить, какие таблицы необходимо дефрагментировать? Это можно выяснить, но у вас будет скрипт.

Вот пример: Предположим, у вас есть таблица mydb.mytable. С включенной innodb_file_per_table у вас есть файл /var/lib/mysql/mydb/mytable.ibd

Вам нужно будет получить два номера

ФАЙЛИЗАЦИЯ ИЗ ОС: Вы можете определить размер файла из ОС, как это

ls -l /var/lib/mysql/mydb/mytable.ibd | awk '{print $5}'

FILESIZE FROM INFORMATION_SCHEMA: Вы можете определить размер файла из файла information_schema.tables следующим образом:

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;
RolandoMySQLDBA
источник
я не думаю, что / var / lib / mysql / ibdata1 очень занят, если вы используете рекомендованный параметр innodb_file_per_table = 1
CrackerJack9
1
@ CrackerJack9 ibdata1 невероятно перегружен из-за того, что в него входит: 1) информация о буфере двойной записи, 2) буфер вставки для вторичных индексов, 3) словарь данных, 4) сегменты отката, 5) отмена табличного пространства. Пожалуйста, зайдите на scribd.com/doc/31337494/XtraDB-InnoDB-internals-in-drawing для наглядного представления этих вещей. Даже с удалением страниц данных и индексов для таблиц InnoDB, ibdata1 все еще может значительно расти в среде с высокой транзакционной средой.
RolandoMySQLDBA
1
@ CrackerJack9 У меня есть дополнительный пост, обсуждающий дополнительную деятельность вокруг ibdata1: dba.stackexchange.com/a/23367/877
RolandoMySQLDBA
Я не понял, что он все еще использовался так сильно. С благодарностью!
CrackerJack9
@RolandoMySQLDBA Можете ли вы заглянуть в кучу, когда у вас есть время?
ypercubeᵀᴹ
5

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

Если вы не используете эту innodb_file_per_tableопцию, единственное, что вы можете с ней сделать, это экспортировать и импортировать базу данных, процедура, требующая много времени и места.

Но если вы используете innodb_file_per_table, вы можете идентифицировать и восстановить это пространство!

До 5.1.21 счетчик свободного пространства доступен из столбца table_comment в information_schema.tables. Вот некоторый SQL для идентификации таблиц с не менее 100 МБ (фактически 97,65 МБ) свободного пространства:

ВЫБЕРИТЕ table_schema, table_name, table_comment FROM
information_schema.tables ГДЕ ДВИГАТЕЛЬ НРАВИТСЯ 'InnoDB' И table_comment RLIKE 'InnoDB free: ([0-9] {6,}). *';

Начиная с 5.1.21, это было перемещено в столбец data_free (гораздо более подходящее место):

ВЫБЕРИТЕ table_schema, table_name, data_free / 1024/1024 AS data_free_MB FROM information_schema.tables ГДЕ ДВИГАТЕЛЬ НРАВИТСЯ 'InnoDB' И data_free> 100 * 1024 * 1024;

Вы можете восстановить потерянное пространство, восстановив таблицу. Лучший способ сделать это - использовать 'alter table', фактически ничего не меняя:

ALTER TABLE `TableName` ENGINE=InnoDB;

Это то, что MySQL делает негласно, если вы запускаете «оптимизацию таблицы» для таблицы InnoDB. Это приведет к блокировке чтения, но не полной блокировке таблицы. Сколько времени это займет, полностью зависит от объема данных в таблице (но не от размера файла данных). Если у вас есть таблица с большим количеством удалений или обновлений, вы можете запускать ее ежемесячно или даже еженедельно.

Махеш Патил
источник
Еще одна вещь, которую я не могу понять, что означает data_free> 100 * 1024 * 1024 ..? И когда я увидел результат, я не могу решить, фрагментирована ли таблица или нет ..? Есть ли способ, чтобы я Можно сказать, что таблица фрагментирована или не фрагментирована.
Абдул Манаф
взгляните на мою часть обновления.
Абдул Манаф