Yakstは、海外の役立つブログ記事などを人力で翻訳して公開するプロジェクトです。
11年以上前投稿 修正あり

InnoDBのB+木リーフノードの整合性チェック

MySQL Performance Blogの翻訳。Percona Data Recovery ToolでInnoDBのインデックス整合性チェックをやってみよう。

原文
Checking B+tree leaf nodes list consistency in InnoDB (English)
原文ライセンス
CC BY-NC-SA
翻訳依頼者
D98ee74ffe0fafbdc83b23907dda3665
翻訳者
D98ee74ffe0fafbdc83b23907dda3665 doublemarket
原著者への翻訳報告
未報告


2013/7/26 by Aleksandr Kuzminsky

InnoDBのページがいくつのレコードを含んでいるかを知るには二通りある。

  • ページヘッダの PAGE_N_RECS フィールドを見る
  • レコード一覧の下限から上限まで全てを確認してレコード数を数える

Percona Data Recovery Tools for InnoDB以前のリビジョン で、 constraints_parser コマンドで出力されたダンプデータに、短いサマリが付くようになった。

しかし、ページが失われてしまって、しかも page_parser がこれを見つけられなかった場合、ページ内の全レコードは失われてしまう。言い換えると、ページごとのリカバリ統計情報は、テーブルのリカバリが完了したかどうかについての情報になり得るわけだ。

この問題をカバーするために、 revision 80 で使用可能になった index_check コマンドがある。

ご存じかもしれないが、InnoDBはテーブルを PRIMARY と呼ばれるクラスタインデックス上に保存する。

InnoDBのPRIMARYインデックス

PRIMARY インデックスは B+ツリー である。全リーフノードが次のリーフノードへのポインタになっているという利点があり、ポインタをたどることで、プライマリキーの順に並んだインデックス全体を読み取ることができる。InnoDBでは、この構造を拡張してあり、前のノードへのポインタも保存している。先頭の前のノードと最後尾の後のノードはNULLになっている。

この知識を元にすると、リストの全要素があるかどうかをチェックできる。あるInnoDBページからリストの最初あるいは最後へ移動することができれば、ページの集合は完璧であるということになる。

これは index_chk コマンドがやっていることだ。このコマンドは、(page_parserコマンドが出力した)InnoDBページが入っているディレクトリからファイルを読み出し、ページのリストを前後にたどろうとする。

例を見てみよう。壊れたInnoDB表領域を用意して、 page_parser で分割している。

 # ./page_parser -f /var/lib/mysql/ibdata1
 Opening file: /var/lib/mysql/ibdata1
 File information:

 ID of device containing file:        64512
 inode number:                     27037954
 protection:                         100660 (regular file)
 number of hard links:                   1
 user ID of owner:                      107
 group ID of owner:                     116
 device ID (if special file):             0
 blocksize for filesystem I/O:         4096
 number of blocks allocated:          86016
 time of last access:            1374662334 Wed Jul 24 06:38:54 2013
 time of last modification:      1374233938 Fri Jul 19 07:38:58 2013
 time of last status change:     1374233938 Fri Jul 19 07:38:58 2013
 total size, in bytes:             44040192 (42.000 MiB)

 Size to process:                  44040192 (42.000 MiB)
 8.26% done. 2013-07-24 08:39:58 ETA(in 00:00 hours). Processing speed: 3637248
 B/sec
 ...
 95.70% done. 2013-07-24 08:40:09 ETA(in 00:00 hours). Processing speed:
 4399053 B/sec
 #

あるインデックスを取り上げて、ページが全て存在するかをチェックしてみよう。

 # ls pages-1374669586/FIL_PAGE_INDEX/0-410/
 00000000-00000145.page  00000000-00000235.page  00000000-00000241.page
 00000000-00000247.page  00000000-00000254.page
 00000000-00000147.page  00000000-00000236.page  00000000-00000243.page
 00000000-00000249.page  00000000-00000255.page
 00000000-00000148.page  00000000-00000239.page  00000000-00000244.page
 00000000-00000251.page
 # ./index_chk -f pages-1374669586/FIL_PAGE_INDEX/0-410
 Couldn't open file
 pages-1374669586/FIL_PAGE_INDEX/0-410/00000000-00000140.page
 #

残念、ID 140のページがなくなっている!

実際のところページ#145の前はページ#140だが、それが消えてしまっている。

 # hexdump -C pages-1374669586/FIL_PAGE_INDEX/0-410/00000000-00000145.page |
 head -2
 00000000  d4 cd 68 41 00 00 00 91  00 00 00 8c ff ff ff ff  |..hA............|
 00000010  00 00 00 00 2b 6c ea 90  45 bf 00 00 00 00 00 00  |....+l..E.......|
 #

気分のいい終わり方のために、全ページそろっているインデックスをチェックした場合も見てみよう。

 # ls pages-1374669586/FIL_PAGE_INDEX/0-2/* # this is SYS_COLUMNS table
 pages-1374669586/FIL_PAGE_INDEX/0-2/00000000-00000010.page
 pages-1374669586/FIL_PAGE_INDEX/0-2/00000000-00002253.page
 pages-1374669586/FIL_PAGE_INDEX/0-2/00000000-00002244.page
 # ./index_chk -f pages-1374669586/FIL_PAGE_INDEX/0-2
 OK
 #

というわけで、テーブルが完全にリカバリできるのは、以下の2つの条件を満たした場合である。

  • grep “Lost records: YES” table.dump | grep -v “Leaf page: NO” が何も返さない
  • ./indexchk -f pages-1374669586/FILPAGEINDEX/<indeid of=”" my=”" table=”"> がOKを返す

次の記事
git rebaseを使うときのルール
前の記事
SQL_SLAVE_SKIP_COUNTER がまずいもう一つの理由

Feed small 記事フィード

新着記事Twitterアカウント