2009年11月10日火曜日

同テーブルの差分を抽出する方法を考えてみる

データベースを管理していると、たまに
「同構成な二つのテーブル内容の差分」
を確認したいときがあります。

例えば、
「1日単位に履歴情報をためていて前日分と本日分との差分を取得したいとき」
とか。

そこでMySQLで上記のことをしたいとき、どういう方法があるか考えてみました。

1.がんばる型
select * from Atable A
inner join Btable B
on A.id = B.id
where
A.column1 != B.column1
or A.column2 != B.column2
or ....;
対応するカラムをwhere句で比較しまくる型。
indexが使えなくないし、カラム追加が発生した時など運用がだるい。
まっさきに思いつく形ではあるが、推奨はできない。


2.運用を少考慮型
select * from Atable
where (column1, column2, column3,...) =
(select * from Btable);
1.よりなるべくカラムを書かない様にした型。
見た目がすっきりした。
ただ副問い合わせを使用しているため、MySQL4.1以降でないと使えない。
リファレンスはこちら
また、カラム追加時の修正は必要なままである。


3.dump型
select * from Atable into outfile '/home/user/atable.tsv';
select * from Btable into outfile '/home/user/btable.tsv';

$ diff -cw /home/user/atable.tsv /home/user/btable.tsv
差分抽出をdiffコマンドに託す型。
丸ごとファイルにdumpするので、カラム追加時の考慮が必要ない。
この型で考慮すべきはソート。
出力順をMySQLに託すのではなく、こちらで指定してあげないと
差分がないのに差分が出力される可能性がある。
また、対象テーブルが1000万レコードを超えるビッグなテーブルだと、
ディスクサイズを考えないといけない(ほぼ3倍になるので)。

<総括>
差分確認バッチ的なのを走らせて確認するなら3、MySQL内でおさめたいのなら2が比較的楽か(カラムの数が少なければ)。