剖析 MySQL InnoDB 记录格式以从原始磁盘恢复
Dissecting MySQL InnoDB record format to restore from raw disk
我有一个 mysql 数据库存储在 USB 拇指驱动器上,该驱动器已经无可挽回地丢失了它的文件分配 table。因此,我无法访问整个 ibdata1 文件。但是我可以找到使用十六进制编辑器使用的记录页面。
所有数据都在那里,但我必须自己读取每条记录并将新的 SQL 语句回放到从 6 个月旧备份恢复的数据库中。
因为有备份,所以知道table结构。并且可以在新数据库中找到一条我知道大致相当于一小块二进制数据的记录。但是,我无法准确确定记录的开始位置和解码记录数据。
table 的 CREATE 语句是:
创建 TABLE <code>ExpenseTransactions
(
idExpenseTransactions
int(11) NOT NULL AUTO_INCREMENT,
TransactionDate
日期时间不为空,
DollarAmount
浮动默认为空,
PoundAmount
浮动默认为空,
Location
varchar(255) 默认为空,
MinorCategory
int(11) 不为空,
Comment
varchar(255) 默认为空,
Recurring
bit(1) NOT NULL DEFAULT b'0',
Estimate
bit(1) NOT NULL DEFAULT b'0',
主键(idExpenseTransactions
),
键 MinorCategory
(MinorCategory
)
) 引擎=InnoDB AUTO_INCREMENT=4687 默认字符集=utf8;
干净的记录如下所示:
'2924', '2013-11-01 00:00:00', '60', NULL, 'George', '66', 'Lawn Maintenance', '1', '0'
接下来是与该记录关联的十六进制字节。我很确定有比重新创建记录所需的更多字节,但我已经标记了我认为是 id 字段以尝试提供一些参考点。
10 06 02 00 01 70 00 41 <b>80 00 0B 6C</b> 00 00 00 00 07 05 86 00 00 01 4A 0E B1 80 00 12 4F 23 1F C1 40 00 00 70 42 6F 47 65 72 67 65 80 00 00 42 4C 61 77 6E 20 4D 61 69 6E 74 65 6E 61 6E 63 65 01 00
我可以很容易地理解字符串,并且可以挑选出构成 MinorCategory 的 4 个字节。最后 2 个字节应表示 2 位值。剩下的就比较难了。
相关记录已正确识别,根据我的博客 post The physical structure of records in InnoDB,解码方式如下:
Header:
10 Length of Comment = 16 bytes
06 Length of Location = 6 bytes
02 Nullable field bitmap (PoundAmount = NULL)
00 Info flags and number of records owned
01 70 Heap number and record type
00 41 Offset to next record = +65 bytes
Record:
80 00 0B 6C idExpenseTransactions = 2924
00 00 00 00 07 05 TRX_ID
86 00 00 01 4A 0E B1 ROLL_PTR
80 00 12 4F 23 1F C1 40 TransactionDate = "2013-11-01 00:00:00"
00 00 70 42 DollarAmount = 60.0
(No data, PoundAmount = NULL)
47 65 6F 72 67 65 Location = "George"
80 00 00 42 MinorCategory = 66
4C 61 77 6E 20 4D 61 69 Comment = "Lawn Maintenance"
6E 74 65 6E 61 6E 63 65 (Comment continues...)
01 Recurring = 1
00 Estimate = 0
我有一个 mysql 数据库存储在 USB 拇指驱动器上,该驱动器已经无可挽回地丢失了它的文件分配 table。因此,我无法访问整个 ibdata1 文件。但是我可以找到使用十六进制编辑器使用的记录页面。
所有数据都在那里,但我必须自己读取每条记录并将新的 SQL 语句回放到从 6 个月旧备份恢复的数据库中。
因为有备份,所以知道table结构。并且可以在新数据库中找到一条我知道大致相当于一小块二进制数据的记录。但是,我无法准确确定记录的开始位置和解码记录数据。
table 的 CREATE 语句是:
创建 TABLE <code>ExpenseTransactions
(
idExpenseTransactions
int(11) NOT NULL AUTO_INCREMENT,
TransactionDate
日期时间不为空,
DollarAmount
浮动默认为空,
PoundAmount
浮动默认为空,
Location
varchar(255) 默认为空,
MinorCategory
int(11) 不为空,
Comment
varchar(255) 默认为空,
Recurring
bit(1) NOT NULL DEFAULT b'0',
Estimate
bit(1) NOT NULL DEFAULT b'0',
主键(idExpenseTransactions
),
键 MinorCategory
(MinorCategory
)
) 引擎=InnoDB AUTO_INCREMENT=4687 默认字符集=utf8;
干净的记录如下所示:
'2924', '2013-11-01 00:00:00', '60', NULL, 'George', '66', 'Lawn Maintenance', '1', '0'
接下来是与该记录关联的十六进制字节。我很确定有比重新创建记录所需的更多字节,但我已经标记了我认为是 id 字段以尝试提供一些参考点。
10 06 02 00 01 70 00 41 <b>80 00 0B 6C</b> 00 00 00 00 07 05 86 00 00 01 4A 0E B1 80 00 12 4F 23 1F C1 40 00 00 70 42 6F 47 65 72 67 65 80 00 00 42 4C 61 77 6E 20 4D 61 69 6E 74 65 6E 61 6E 63 65 01 00
我可以很容易地理解字符串,并且可以挑选出构成 MinorCategory 的 4 个字节。最后 2 个字节应表示 2 位值。剩下的就比较难了。
相关记录已正确识别,根据我的博客 post The physical structure of records in InnoDB,解码方式如下:
Header:
10 Length of Comment = 16 bytes
06 Length of Location = 6 bytes
02 Nullable field bitmap (PoundAmount = NULL)
00 Info flags and number of records owned
01 70 Heap number and record type
00 41 Offset to next record = +65 bytes
Record:
80 00 0B 6C idExpenseTransactions = 2924
00 00 00 00 07 05 TRX_ID
86 00 00 01 4A 0E B1 ROLL_PTR
80 00 12 4F 23 1F C1 40 TransactionDate = "2013-11-01 00:00:00"
00 00 70 42 DollarAmount = 60.0
(No data, PoundAmount = NULL)
47 65 6F 72 67 65 Location = "George"
80 00 00 42 MinorCategory = 66
4C 61 77 6E 20 4D 61 69 Comment = "Lawn Maintenance"
6E 74 65 6E 61 6E 63 65 (Comment continues...)
01 Recurring = 1
00 Estimate = 0