愛と勇気と缶ビール

ふしぎとぼくらはなにをしたらよいか

SQL_SLAVE_SKIP_COUNTERについて教えてもらったよ

何らかの理由でmasterとslaveの間で不整合があって、「既にテーブルがある」とか「UNIQUE制約にひっかかる」とかそういう理由でreplicationが止まっている時は、

SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
start slave;
show slave status; (確認)

って風に一つスキップするんだよ、ってnekokakさんに教えてもらったよ。 普通は慎重を期して1つずつスキップするものらしいんだよ。

こんなのDBの運用とかバリバリやってる人にとっては当たり前かもしれないけど、そんなので一々恥ずかしがってたら前に進めないのでblogに書くんだよ。


で、MySQL 5.0の該当リファレンス↓
http://dev.mysql.com/doc/refman/5.0/en/set-global-sql-slave-skip-counter.html

ステートメントベースのreplicationの場合にこれをやるとなんとなく1ステートメントがスキップされるように思えるけど、このリファレンスには 「これ(SET GLOBAL...)を使うときはバイナリログが実はevent groupのシーケンスから成っていることを理解する必要がある」と書いてあるんだよ。


event groupの定義も書いてあって

  • transactionalなtableの場合、event groupとは1トランザクションのことを指す
  • nontransactionalなtableの場合、event groupとは1つのSQLステートメントのことを指す

この定義によると、僕等が普段使うことの多いInnoDBなtableについては "event group" = "1 transaction" ということになる。

そのさらに下に、「スキップしてevent groupの途中まで行った場合、そのevent groupの最後までのeventがスキップされる」と書いてある。

なんとなんと、SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; でのスキップは、transactionalなtableの場合はステートメントではなくてトランザクション単位だったのか。


さらにさらに、誰かがリファレンスにコメントをつけている、と思ったらなんとそれはバロン・シュワルツ先生でした。泣く子も黙る「実践ハイパフォーマンスMySQL」の著者でありほげほげでふがふがな人ですね。


バロン先生はこういっています

「この変数を設定するのは、他の変数を設定するのとはわけがちがう。この変数を後から読み出すことはできないし、実際のところglobalな変数でもありゃしない。それどころか、こいつはslave threadだけが読める変数なんだ。」

おやおや、バロン先生からみてもこいつは変わり者のようです。


「start slaveを打ってslave threadを再開すると、slaveはstatementをスキップしてこの変数が0になるまでデクリメントする。元の値を後から見たい場合、show slave statusしてSkip_Counterのところを見るしかないね。」

ほうほう。


「この変数は設定しても、すぐ変わってしまう。例えば、1をセットしてstart slaveし、後でまたコケた場合にはそれは0に戻っている。エラーが起こっているやつをもっぺんスキップしたいなら、また1にセットするといい。」

なるほどう。