LINUX.ORG.RU
ФорумAdmin

MySQL, ошибка восстановления после mysqlhotcopy --noindices

 , ,


0

1

Кажется, пора попросить помощь зала^W лора:

TL;DR: myisamchk -rq не восстанавливает файл индексов после mysqlhotcopy --noindices.

Есть узкоспециализированный софт, работающий на RHEL. Он использует MySQL и выполняет резервное копирование своих баз данных с помощью mysqlhotcopy --noindices. Восстановление из резервной копии включает шаг myisamchk -rq и на одной из таблиц завершается с ошибкой:

/usr/bin/myisamchk: Unknown error 126
myisamchk: error: '/var/lib/mysql/db/Foo.MYI' doesn't have a correct index definition. You need to recreate it before you can do a repair
# ls -l /var/lib/mysql/db/Foo.MYI
rw-r--r-- 1 mysql mysql  2048 Jul 21 01:02 /var/lib/mysql/db/Foo.MYI
# mysql db
mysql> check table Foo;
+--------+-------+----------+-----------------------------------------------------------------+
| Table  | Op    | Msg_type | Msg_text                                                        |
+--------+-------+----------+-----------------------------------------------------------------+
| db.Foo | check | Error    | Incorrect key file for table './db/Foo'; try to repair it       |
| db.Foo | check | Error    | Incorrect key file for table 'Foo'; try to repair it            |
| db.Foo | check | error    | Corrupt                                                         |
+--------+-------+----------+-----------------------------------------------------------------+

После truncate, размер файла индексов увеличивается (2048 -> 3072) и таблица проходит проверку:

mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

mysql> truncate table Foo;
Query OK, 0 rows affected (0.01 sec)

mysql> check table Foo;
+--------+-------+----------+----------+
| Table  | Op    | Msg_type | Msg_text |
+--------+-------+----------+----------+
| db.Foo | check | status   | OK       |
+--------+-------+----------+----------+
1 row in set (0.01 sec)

mysql> select * from Foo;
Empty set (0.01 sec)
# ls -l /var/lib/mysql/db/Foo.*
-rw-rw---- 1 mysql mysql 30482 Mar  3 08:03 /var/lib/mysql/db/Foo.frm
-rw-rw---- 1 mysql mysql     0 Jul 21 01:02 /var/lib/mysql/db/Foo.MYD
-rw-r--r-- 1 mysql mysql  3072 Jul 21 01:02 /var/lib/mysql/db/Foo.MYI

Но при следующем резервном копировании (даже пустой таблицы) ситуация повторяется...

★★

Ответ на: комментарий от kto_tama

Делал, воспроизводится. Если удалить эту таблицу, то копирование-восстановление работает нормально.

Может такое быть, из-за отсутствия собственно данных? Софт на этапе установки и настройки, многие таблицы базы ещё пустые.

Evenik ★★
() автор топика
Последнее исправление: Evenik (всего исправлений: 1)
Ответ на: комментарий от firkax

repair table что пишет?

Тоже, что и check table:

mysql> repair table Foo;
+--------+--------+----------+-----------------------------------------------------------------+
| Table  | Op     | Msg_type | Msg_text                                                        |
+--------+--------+----------+-----------------------------------------------------------------+
| db.Foo | repair | Error    | Incorrect key file for table './db/Foo'; try to repair it       |
| db.Foo | repair | Error    | Incorrect key file for table 'Foo'; try to repair it            |
| db.Foo | repair | error    | Corrupt                                                         |    
+--------+--------+----------+-----------------------------------------------------------------+

Evenik ★★
() автор топика

В порядке догадки: может таблица создана когда-то давно другой версией базы или у неё какие-то особенности в списке ключей/формате (foreign keys или ещё какая экзотика).

Пересобери ключи на исходном сервере (вроде repair table это делает, ну или можно создать новую таблицу и перенести в неё все данные). Ну и посмотри что там с форматом ключей - они все полностью обычные или нет.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Спасибо, попробую, о результатах напишу.

Ещё хотел спросить, что делает mysqlhotcopy --noindices с индексами?

Выглядит как простое удаление килобайта данных в конце файла:

# ls -l /var/lib/mysql/db/Foo.*
-rw-rw---- 1 mysql mysql 30482 Mar  3 08:03 /var/lib/mysql/db/Foo.frm
-rw-rw---- 1 mysql mysql     0 Jul 21 13:54 /var/lib/mysql/db/Foo.MYD
-rw-r--r-- 1 mysql mysql  3072 Jul 21 13:55 /var/lib/mysql/db/Foo.MYI
# dd if=/var/lib/mysql/db/Foo.MYI count=4 | md5sum                    
4+0 records in
4+0 records out
2048 bytes (2.0 kB) copied, 0.000123837 s, 16.5 MB/s
bc2cfb6051021ebe2df4ebf5c459ff01  -
# mysqlhotcopy --noindices db /root/foo
...
# ls -l foo/db/Foo.*
-rw-rw---- 1 mysql mysql 30482 Mar  3 08:03 foo/db/Foo.frm
-rw-rw---- 1 mysql mysql     0 Jul 21 13:54 foo/db/Foo.MYD
-rw-r--r-- 1 root  root   2048 Jul 21 13:58 foo/db/Foo.MYI
# md5sum foo/db/Foo.MYI
bc2cfb6051021ebe2df4ebf5c459ff01  foo/db/Foo.MYI
Evenik ★★
() автор топика
Ответ на: комментарий от Evenik

Ещё хотел спросить, что делает mysqlhotcopy --noindices с индексами?

Не знаю. mysqlhotcopy это perl-скрипт, за работу этой опции отвечает функция copy_index (открой в текстовом редакторе). Если знаешь perl может разберёшься. Судя по тому что там встречается число 2048 - возможно она просто копирует первые 2кб.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ну и посмотри что там с форматом ключей - они все полностью обычные или нет

Дамп таблицы (имена столбцов как и прочего изменил для наглядности):

# mysqldump db Foo
-- MySQL dump 10.13  Distrib 5.1.73, for redhat-linux-gnu (x86_64)
--
-- Host: localhost    Database: db
-- ------------------------------------------------------
-- Server version       5.1.73

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

--
-- Table structure for table `Foo`
--

DROP TABLE IF EXISTS `Foo`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `Foo` (
  `Col_1` smallint(6) NOT NULL,
  `Col_2` smallint(6) NOT NULL,
  `Col_3` smallint(6) NOT NULL,
  `Col_4` int(11) NOT NULL AUTO_INCREMENT,
  `Col_5` smallint(6) DEFAULT NULL,
  `Col_6` int(11) NOT NULL,
  `Col_7` smallint(6) NOT NULL,
  `Col_8` smallint(6) NOT NULL,
  `Col_9` int(11) DEFAULT NULL,
  `Col_10` smallint(6) DEFAULT NULL,
  `Col_11` smallint(6) DEFAULT NULL,
  `Col_12` varchar(64) DEFAULT NULL,
  `Col_13` smallint(6) DEFAULT NULL,
  `Col_14` int(11) DEFAULT NULL,
  `Col_15` smallint(6) DEFAULT NULL,
  `Col_16` smallint(6) DEFAULT NULL,
  `Col_17` smallint(6) DEFAULT NULL,
  `Col_18` smallint(6) DEFAULT NULL,
  `Col_19` smallint(6) DEFAULT NULL,
  `Col_20` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `Col_21` smallint(6) DEFAULT NULL,
  `Col_22` int(11) DEFAULT NULL,
  `Col_23` smallint(6) DEFAULT NULL,
  `Col_24` smallint(6) DEFAULT '4000',
  `Col_25` smallint(6) DEFAULT '1000',
  `Col_26` smallint(6) DEFAULT '5000',
  `Col_27` smallint(6) DEFAULT '511',
  `Col_28` smallint(6) DEFAULT '5',
  `Col_29` smallint(6) DEFAULT '500',
  `Col_30` smallint(6) DEFAULT '4000',
  `Col_31` smallint(6) DEFAULT '1000',
  `Col_32` smallint(6) DEFAULT '5000',
  `Col_33` smallint(6) DEFAULT '511',
  `Col_34` smallint(6) DEFAULT '5',
  `Col_35` smallint(6) DEFAULT '500',
  `Col_36` int(11) DEFAULT NULL,
  `Col_37` smallint(6) NOT NULL,
  `Col_38` smallint(6) DEFAULT NULL,
  `Col_39` smallint(6) DEFAULT NULL,
  `Col_40` varchar(64) DEFAULT NULL,
  `Col_41` double DEFAULT '0',
  `Col_42` double DEFAULT '0',
  `Col_43` double DEFAULT '-25',
  `Col_44` smallint(6) DEFAULT '1',
  `Col_45` double DEFAULT '0',
  `Col_46` smallint(6) DEFAULT '0',
  `Col_47` smallint(6) DEFAULT '0',
  `Col_48` int(11) DEFAULT '250',
  `Col_49` double DEFAULT '0',
  `Col_50` varchar(32) DEFAULT NULL,
  `Col_51` smallint(6) DEFAULT NULL,
  `Col_52` smallint(6) DEFAULT '0',
  `Col_53` int(11) DEFAULT '0',
  `Col_54` smallint(6) DEFAULT '0',
  `Col_55` smallint(6) DEFAULT '0',
  `Col_56` tinyint(4) DEFAULT '0',
  `Col_57` varchar(16) DEFAULT NULL,
  `Col_58` int(11) DEFAULT NULL,
  `Col_59` varchar(16) DEFAULT NULL,
  `Col_60` int(11) DEFAULT NULL,
  `Col_61` smallint(6) DEFAULT '70',
  `Col_62` smallint(6) DEFAULT '70',
  `Col_63` tinyint(4) DEFAULT '0',
  `Col_64` tinyint(4) DEFAULT '1',
  `Col_65` int(11) DEFAULT '1',
  `Col_66` int(11) DEFAULT '2',
  `Col_67` int(11) DEFAULT '0',
  `Col_68` int(11) DEFAULT '0',
  `Col_69` int(11) DEFAULT '3',
  `Col_70` int(11) DEFAULT '4',
  `Col_71` tinyint(4) DEFAULT '0',
  `Col_72` double DEFAULT '0',
  `Col_73` tinyint(4) DEFAULT '0',
  `Col_74` int(11) DEFAULT '0',
  `Col_75` int(11) DEFAULT '0',
  `Col_76` int(11) DEFAULT '0',
  `Col_77` int(11) DEFAULT '0',
  `Col_78` int(11) DEFAULT '2',
  `Col_79` int(11) DEFAULT '2',
  `Col_80` float DEFAULT '1',
  `Col_81` float DEFAULT '1',
  `Col_82` int(11) DEFAULT '-1',
  `Col_83` int(11) DEFAULT '-1',
  `Col_84` int(11) DEFAULT '0',
  `Col_85` int(11) DEFAULT '0',
  `Col_86` tinyint(4) DEFAULT '0',
  `Col_87` tinyint(4) DEFAULT '0',
  `Col_88` tinyint(4) DEFAULT '0',
  `Col_89` tinyint(4) DEFAULT '0',
  `Col_90` double DEFAULT '1',
  `Col_91` double DEFAULT '1',
  `Col_92` double DEFAULT '1',
  `Col_93` double DEFAULT '1',
  `Col_94` double DEFAULT '0',
  `Col_95` tinyint(4) DEFAULT '0',
  `Col_96` tinyint(4) DEFAULT '1',
  `Col_97` tinyint(4) DEFAULT '0',
  `Col_98` tinyint(4) DEFAULT '0',
  `Col_99` text,
  `Col_100` text,
  `Col_101` int(10) unsigned DEFAULT NULL,
  `Col_102` smallint(6) DEFAULT '0',
  `Col_103` tinyint(4) DEFAULT '0',
  `Col_104` varchar(255) DEFAULT NULL,
  `Col_105` varchar(255) DEFAULT NULL,
...
Evenik ★★
() автор топика
Ответ на: комментарий от Evenik

Продолжение:

...
  `Col_106` varchar(64) DEFAULT NULL,
  `Col_107` varchar(255) DEFAULT NULL,
  `Col_108` smallint(5) unsigned DEFAULT '0',
  `Col_109` tinyint(1) DEFAULT '0',
  `Col_110` int(10) unsigned DEFAULT '0',
  `Col_111` tinyint(1) DEFAULT '0',
  `Col_112` tinyint(1) DEFAULT '0',
  `Col_113` tinyint(4) DEFAULT '0',
  `Col_114` double DEFAULT '0',
  `Col_115` double DEFAULT '0',
  `Col_116` double DEFAULT '0',
  `Col_117` int(11) DEFAULT '1',
  `Col_118` varchar(16) DEFAULT NULL,
  `Col_119` int(11) DEFAULT '0',
  `Col_120` tinyint(1) DEFAULT '0',
  `Col_121` int(11) DEFAULT '0',
  `Col_122` smallint(6) DEFAULT '64',
  `Col_123` smallint(6) DEFAULT '128',
  `Col_124` tinyint(4) DEFAULT '0',
  `Col_125` tinyint(4) DEFAULT '1',
  `Col_126` double DEFAULT '9',
  `Col_127` double DEFAULT '0',
  `Col_128` double DEFAULT '0',
  `Col_129` varchar(12) DEFAULT '4800, 8N1',
  `Col_130` varchar(10) DEFAULT 'ttyS0',
  `Col_131` int(10) unsigned NOT NULL DEFAULT '2',
  `Col_132` int(11) DEFAULT '0',
  `Col_133` smallint(5) unsigned NOT NULL,
  `Col_134` int(11) DEFAULT '0',
  `Col_135` int(11) DEFAULT '0',
  `Col_136` int(10) unsigned NOT NULL DEFAULT '0',
  `Col_137` varchar(255) DEFAULT NULL,
  `Col_138` smallint(6) DEFAULT '0',
  `Col_139` int(11) NOT NULL DEFAULT '0',
  `Col_140` tinyint(1) DEFAULT '0',
  `Col_141` tinyint(1) DEFAULT '0',
  `Col_142` int(11) DEFAULT '60',
  `Col_143` smallint(6) DEFAULT '0',
  `Col_144` double DEFAULT '0',
  `Col_145` double DEFAULT '-1',
  `Col_146` double(40,20) DEFAULT NULL,
  `Col_147` double(10,1) DEFAULT '25.0',
  `Col_148` double(40,20) DEFAULT NULL,
  `Col_149` smallint(6) DEFAULT NULL,
  `Col_150` smallint(6) NOT NULL DEFAULT '0',
  `Col_151` tinyint(4) DEFAULT '0',
  `Col_152` tinyint(4) DEFAULT '0',
  `Col_153` tinyint(4) DEFAULT '0',
  `Col_154` int(11) DEFAULT '0',
  `Col_155` int(11) DEFAULT '0',
  `Col_156` double DEFAULT '0',
  `Col_157` double DEFAULT '0',
  `Col_158` int(11) DEFAULT '0',
  `Col_159` tinyint(1) DEFAULT '1',
  `Col_160` tinyint(1) DEFAULT '0',
  `Col_161` smallint(11) DEFAULT '0',
  `Col_162` varchar(10) DEFAULT '0x8100',
  `Col_163` varchar(10) DEFAULT '0x8100',
  `Col_164` smallint(11) DEFAULT '0',
  `Col_165` int(11) DEFAULT '0',
  `Col_166` int(11) DEFAULT '0',
  `Col_167` int(11) DEFAULT '1540',
  `Col_168` tinyint(4) DEFAULT '1',
  `Col_169` tinyint(4) DEFAULT '0',
  `Col_170` tinyint(4) DEFAULT '0',
  `Col_171` tinyint(4) DEFAULT '0',
  `Col_172` varchar(256) DEFAULT NULL,
  `Col_173` varchar(51) DEFAULT NULL,
  `Col_174` tinyint(4) NOT NULL DEFAULT '0',
  `Col_175` varchar(20) DEFAULT '0.0.0.0',
  `Col_176` varchar(20) DEFAULT '255.255.255.0',
  `Col_177` int(10) unsigned NOT NULL DEFAULT '0',
  `Col_178` double DEFAULT '1',
  `Col_179` double DEFAULT '0.6',
  `Col_180` tinyint(4) DEFAULT '0',
  PRIMARY KEY (`Col_4`),
  UNIQUE KEY `KFoo` (`Col_1`,`Col_2`,`Col_3`,`Col_4`),
  KEY `Col_1` (`Col_1`,`Col_5`),
  KEY `Col_8` (`Col_8`),
  KEY `Col_9` (`Col_9`),
  KEY `Col_13` (`Col_13`),
  KEY `Col_14` (`Col_14`),
  KEY `i_Col_39` (`Col_39`),
  KEY `i_Col_138` (`Col_138`),
  KEY `i_Col_143` (`Col_143`),
  KEY `i_Col_53` (`Col_53`),
  KEY `i_Col_134` (`Col_134`),
  KEY `i_Col_110` (`Col_110`),
  KEY `i_Col_70` (`Col_70`),
  KEY `i_Col_66` (`Col_66`),
  KEY `i_Col_75` (`Col_75`),
  KEY `i_Col_132` (`Col_132`),
  KEY `i_Col_133` (`Col_133`),
  KEY `i_Col_5` (`Col_5`),
  KEY `i_Col_37` (`Col_37`),
  KEY `i_Col_101` (`Col_101`),
  KEY `i_Col_54` (`Col_54`),
  KEY `i_Col_135` (`Col_135`),
  KEY `i_Col_6` (`Col_6`),
  KEY `i_Col_7` (`Col_7`),
  KEY `i_Col_3` (`Col_3`),
  KEY `i_Col_2` (`Col_2`),
  KEY `i_Col_11` (`Col_11`),
  KEY `i_Col_1` (`Col_1`),
  KEY `i_Col_10` (`Col_10`),
  KEY `i_Col_69` (`Col_69`),
  KEY `i_Col_65` (`Col_65`),
  KEY `i_Col_74` (`Col_74`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

--
-- Dumping data for table `Foo`
--

LOCK TABLES `Foo` WRITE;
/*!40000 ALTER TABLE `Foo` DISABLE KEYS */;
/*!40000 ALTER TABLE `Foo` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

-- Dump completed on 2022-07-21 21:52:22

Evenik ★★
() автор топика
Ответ на: комментарий от firkax

Возможно проблема в том что в ней слишком много столбцов/ключей и они в 2кб заголовок не влезают. У остальных таблиц 2кб получается после truncate?

Ещё раз спасибо за помощь!

Чертовски может быть, эта таблица (Foo) с самым большим файлом индексов:

# mysql -Nse 'show tables' db | while read table; do mysql -e "truncate table $table" db; done
# ls -l /var/lib/mysql/db/*.MYI | wc -l
124
# ls -l /var/lib/mysql/db/*.MYI | sed -E 's/ +/\t/g' | cut -f5 | sort -nu
1024
2048
3072
# ls -l /var/lib/mysql/db/*.MYI | grep -E '2048|3072'
-rw-r--r--      1       mysql   mysql   3072    Jul     21      23:10   /var/lib/mysql/db/Foo.MYI
-rw-r--r--      1       mysql   mysql   2048    Jul     21      23:10   /var/lib/mysql/db/FooBar.MYI

Смущает только, что это довольно стабильный ынтерпрайз, странно было бы пропустить такое...

Evenik ★★
() автор топика
Последнее исправление: Evenik (всего исправлений: 1)
Ответ на: комментарий от anc

ебселевскую таблицу перенесли?

имена столбцов как и прочего изменил для наглядности

Почему не mysqldump ?

Там участвует и mysqldump и mysqlhotcopy. Не знаю почему, не я это писал.

Evenik ★★
() автор топика
Ответ на: комментарий от firkax

Возможно проблема в том что в ней слишком много столбцов/ключей и они в 2кб заголовок не влезают.

Почитал документацию по mysqlhotcopy:

# man mysqlhotcopy
    --noindices    Do not include full index files for MyISAM tables in the backup. This makes the backup smaller and faster. The indexes for reloaded tables can be reconstructed later with myisamchk -rq.
# perldoc /usr/bin/mysqlhotcopy
    --noindices    Don’t include index files in copy. Only up to the first 2048 bytes are copied;  You can restore the indexes with isamchk -r or myisamchk -r on the backup.

Почуму же myisamchk -r не справляется?

Evenik ★★
() автор топика
Последнее исправление: Evenik (всего исправлений: 1)
Ответ на: комментарий от Evenik

имена столбцов как и прочего изменил для наглядности

Я не про наименование столбцов, а про их количество. Таблица на 180 столбцов намекает, что что-то с проектированием базы пошло не так. :)

anc ★★★★★
()
Ответ на: комментарий от anc

Таблица на 180 столбцов намекает, что что-то с проектированием базы пошло не так. :)

Возможно. Во всём мире прямых пользователей несколько сотен (если не десятков). Сон [общественного] разума рождает чудовищ ;-)

Evenik ★★
() автор топика
Последнее исправление: Evenik (всего исправлений: 1)
Ответ на: комментарий от Evenik

Ну так поменяй там в скрипте 2048 на 3072, делов то. Не справляется потому что заголовок индексного файла всё-таки нужен полностью. Хотя, возможно, требование наличия заголовка тут исключительно потому, что авторы mysql не предусмотрели такой случай, а не потому, что в нём какие-то невосстанавливаемые данные, но что есть то есть.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от Evenik

Смущает только, что это довольно стабильный ынтерпрайз, странно было бы пропустить такое...

Никакой это не энтерпрайз, даже сам mysql. А mysqlhotcopy это прилепленный сбоку чей-то скрипт.

firkax ★★★★★
()
Ответ на: комментарий от Evenik

Там участвует и mysqldump и mysqlhotcopy. Не знаю почему, не я это писал.

Потому что mysqldump на огромную таблицу положит базу на час. Не слушай anc'а, он оторванный от реальности скриптотеоретик.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Ну так поменяй там в скрипте 2048 на 3072

Поменял, ожидаемо работает, но осталось чувство неудовлетворённости.

Хотел задать вопрос на форуме MySQL, но Oracle похерили мой аккаунт по признаку гражданства (не обижаюсь).

Спросил у более широкой аудитории (пока без ответа): https://serverfault.com/questions/1106355/mysql-myisamchk-recover-error-after...

Спасибо firkax и всем, кто помогал!

Evenik ★★
() автор топика