« Pathtraq リニューアルのおしらせ (リアルタイム検索機能の追加ほか) | メイン | setlock を使って cron をぶんまわす方法 »

2008年01月29日

データベースをコピーするモジュール DBIx::Replicate

 データベースをオンデマンドでコピーするモジュール DBIx::Replicate を書いて、CodeRepos にアップロードしました。こんな感じで使います。

use DBIx::Replicate qw/dbix_replicate/;

# 20才以下の人だけを young_table にコピー (1000行毎, 最大負荷 0.5)
dbix_replicate({
    src_conn     => $dbh,
    src_table    => 'all_people',
    dst_conn     => $dbh,
    dest_table   => 'young_people',
    primary_keys => [ qw/id/ ],
    columns      => [ qw/id name age/ ],
    block        => 1000,
    load         => 0.5,
    extra_cond   => 'age<20',
});

# zipcode 毎にクエリを分割してテーブル全体をコピー
dbix_replicate({
    src_conn     => $src_dbh,
    src_table    => 'tbl',
    dest_conn    => $dest_dbh,
    dest_table   => 'tbl',
    copy_by      => [ qw/zipcode/ ],
});

 1回のクエリで転送する量を行数あるいはカラムの値で制限することができるので、テーブルをダンプしての転送やレプリケーションよりも柔軟な運用が可能かと思います。もちろん、コピーできるテーブルの大きさに制限もありません。たとえば、以下のような場合に便利かもしれません。

  • 異なるRDBMS間でデータをコピーしたい
  • インクリメンタルコピーでいいから、転送中に発生するロックを最小限にしたい
  • 絞り込みを行いつつデータをコピーしたい
  • InnoDB を使っているが mysqldump --single-transaction | ssh mysql 等だとメモリ負荷が大きい

 現状の問題としては、以下のようなものがあります。

  • トランザクションを使っているので MyISAM のコピーには使えない
  • MySQL は delete の条件節内の (min_a,min_b)<=(a,b) and (a,b)<(max_a,min_b) をrangeクエリに最適化してくれないので、複合プライマリキーをコピーする場合には、上の使用例の下のタイプである copy_by を使う必要がある

といったあたりです。もともと手元で動かしていたものを、ユニットテストを書きたくなったがために分割してモジュール化したので ad-hoc なコードですがご容赦いただければ。誰か OO な設計にリファクターして、いろんなコピー戦略を実装できるようにしてくれないかなぁ。

投稿者 kazuho : 2008年01月29日 16:03 このエントリーを含むはてなブックマーク このエントリーを含むはてなブックマーク

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1747

このリストは、次のエントリーを参照しています: データベースをコピーするモジュール DBIx::Replicate:

» DBIx::Replicateのリファクタリング from D-6 [相変わらず根無し]
誰か OO な設計にリファクターして、いろんなコピー戦略を実装できるようにしてく... [続きを読む]

トラックバック時刻: 2008年01月29日 20:50