Статьи

Как восстановить потерянный файл .ibd с MySQL 5.6

Это сообщение от  Майкла Рикмаса из MySQL Performance Blog.

Несколько лет назад Ив Трюдо и Александр Кузьминский писали сообщения о различных способах восстановления потерянных файлов .ibd:

Сегодня я хочу показать вам, как это сделать проще и быстрее. В моем примере я восстановлю файл payment.ibd (таблица платежей) из Sakila DB на сервере с MySQL 5.5 (но с помощью MySQL 5.6 и песочницы ).

В моем случае ОС CentOS. Поэтому мне нужно было:

wget http://www.percona.com/redir/downloads/Percona-Server-5.6/LATEST/release-5.6.14-62.0/483/binary/linux/i686/Percona-Server-5.6.14-rel62.0-483.Linux.i686.tar.gz

Создать песочницу:

make_sandbox Percona-Server-5.6.14-rel62.0-483.Linux.i686.tar.gz

Попробуй это:

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "select @@version\G"
*************************** 1. row ***************************
@@version: 5.6.14-rel62.0

Оно работает!

Проверьте datadir и включена ли опция innodb_file_per_table (это требование):

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "show variables like 'datadir'"
+---------------+---------------------------------------+
| Variable_name | Value                                 |
+---------------+---------------------------------------+
| datadir       | /home/mixa/sandboxes/msb_5_6_14/data/ |
+---------------+---------------------------------------+
mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "show variables like '%per_table'"
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON    |
+-----------------------+-------+

Если он не включен, то вам нужно включить его

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "SET GLOBAL innodb_file_per_table=1"

Создать пустую таблицу платежей на песочнице 5.6

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 test < payment_table.sql

Payment_table.sql — файл с выпиской «SHOW CREATE TABLE» для таблицы платежей. Структура таблицы должна быть одинаковой.

cat payment_table.sql
CREATE TABLE `payment` (
  `payment_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` smallint(5) unsigned NOT NULL,
  `staff_id` tinyint(3) unsigned NOT NULL,
  `rental_id` int(11) DEFAULT NULL,
  `amount` decimal(5,2) NOT NULL,
  `payment_date` datetime NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`payment_id`),
  KEY `idx_fk_staff_id` (`staff_id`),
  KEY `idx_fk_customer_id` (`customer_id`),
  KEY `fk_payment_rental` (`rental_id`)
) ENGINE=InnoDB

Стоп песочница

./sandboxes/msb_5_6_14/stop

Замените файл .ibd (в моем случае его правильная копия находится в моем домашнем каталоге)

cp ~/payment.ibd ~/sandboxes/msb_5_6_14/data/test/ -f

Убедитесь, что разрешения для .ibd файла в порядке

sudo chmod 660 ~/sandboxes/msb_5_6_14/data/test/payment.ibd
sudo chown : ~/sandboxes/msb_5_6_14/data/test/payment.ibd

Начать песочницу

./sandboxes/msb_5_6_14/start

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

Выбрать из таблицы

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "select count(*) from test.payment"
ERROR 2013 (HY000) at line 1: Lost connection to MySQL server during query
mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "select count(*) from test.payment"
ERROR 1146 (42S02) at line 1: Table 'test.payment' doesn't exist

Журнал ошибок

2013-11-02 14:36:34 b7eff990  InnoDB: Error: table 'test/payment'
InnoDB: in InnoDB data dictionary has tablespace id 7,
InnoDB: but a tablespace with that id does not exist. There is
InnoDB: a tablespace of name test/payment and id 10, though. Have
InnoDB: you deleted or moved .ibd files?
...  ...
2013-11-02 14:36:36 11640 [ERROR] InnoDB: Failed to find tablespace for table '"test"."payment"' in the cache. Attempting to load the tablespace with space id 7.
2013-11-02 14:36:36 11640 [ERROR] InnoDB: In file './test/payment.ibd', tablespace id and flags are 10 and 0, but in the InnoDB data dictionary they are 7 and 0. Have you moved InnoDB .ibd files around without using the commands DISCARD TABLESPACE and IMPORT TABLESPACE? Please refer to http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting-datadict.html for how to resolve the issue.
2013-11-02 14:36:36 a31a2b90  InnoDB: Operating system error number 2 in a file operation.
InnoDB: The error means the system cannot find the path specified.
2013-11-02 14:36:36 11640 [ERROR] InnoDB: Could not find a valid tablespace file for 'test/payment'. See http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting-datadict.html for how to resolve the issue.
2013-11-02 14:36:36 a31a2b90 InnoDB: cannot calculate statistics for table "test"."payment" because the .ibd file is missing. For help, please refer to http://dev.mysql.com/doc/refman/5.6/en/innodb-troubleshooting.html

Как это исправить? В 5.6 управление табличным пространством очень улучшено, поэтому нужно только «ALTER TABLE .. DISCARD TABLESPACE» и «ALTER TABLE .. IMPORT TABLESPACE».

Пожалуйста, проверьте также ограничения: Ограничения копирования табличных пространств

Посмотрите на пример:

Отменить табличное пространство

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "alter table test.payment discard tablespace; show warnings;"
+---------+------+--------------------------------------------------------+
| Level   | Code | Message                                                |
+---------+------+--------------------------------------------------------+
| Warning | 1812 | InnoDB: Tablespace is missing for table 'test/payment' |
| Warning | 1812 | InnoDB: Tablespace is missing for table 'payment'      |
+---------+------+--------------------------------------------------------+

Импорт табличного пространства

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "alter table test.payment import tablespace; show warnings"
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                      |
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1810 | InnoDB: IO Read error: (2, No such file or directory) Error opening './test/payment.cfg', will attempt to import without schema verification |
+---------+------+----------------------------------------------------------------------------------------------------------------------------------------------+

Вот и все, данные восстановлены, таблица выплат доступна на 5.6 песочнице.

Теперь проверьте, есть ли данные в таблице платежей в песочнице:

mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "select count(*) from test.payment"
+----------+
| count(*) |
+----------+
|    16049 |
+----------+
mysql -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 -e "select * from test.payment limit 1\G"
*************************** 1. row ***************************
  payment_id: 1
 customer_id: 1
    staff_id: 1
   rental_id: 76
      amount: 2.99
payment_date: 0000-00-09 03:49:32
 last_update: 2028-02-08 12:32:35

Существует.

Так что выкинь его из песочницы и восстанови на 5.5:

Дамп из 5.6

mysqldump -umsandbox -pmsandbox --host=127.0.0.1 --port=5614 --add-drop-table test payment > ~/payment_dump.sql

Восстановить до 5.5

mysql -u user -p  < ~/payment_dump.sql

Проверьте, существуют ли данные на 5.5

mysql -u root -e "select * from test.payment limit 3;"
+------------+-------------+----------+-----------+--------+---------------------+---------------------+
| payment_id | customer_id | staff_id | rental_id | amount | payment_date        | last_update         |
+------------+-------------+----------+-----------+--------+---------------------+---------------------+
|          1 |           1 |        1 |        76 |   2.99 | 0000-00-09 03:49:32 | 2028-02-08 12:32:35 |
|          2 |           1 |        1 |       573 |   0.99 | 0000-00-09 03:49:32 | 0000-00-00 00:00:00 |
|          3 |           1 |        1 |      1185 |   5.99 | 0000-00-09 03:49:37 | 0000-00-00 00:00:00 |
+------------+-------------+----------+-----------+--------+---------------------+---------------------+

Во время моей работы с этим делом я попал в ситуацию, в которой оплата в дроп-таблице на 5.5 была невозможна, потому что payment.idb там не был корректным — поэтому сервер каждый раз падал, когда я пытался получить доступ к этой таблице. Для устранения этой проблемы:
— остановка сервера
— гт .ibd файл
— Запуск сервера
— удаление таблицы , как правило , с помощью DROP TABLE команды