経緯
MySQLのチューニングのため、大量のデータを入れてパフォーマンスを計測する作業が必要となった。
Data::Generator::FromDDLというPerlライブラリがあるので、それを使ってダミーデータを入れることにした。 https://github.com/addsict/Data-Generator-FromDDL
手順
MySQLのmydbデータベースに、すでにcreate tableされているとする。まず、MySQLに付属しているmysqldumpというツールを使って、すでにmydbに作られたテーブルを再現してcreate tableするだけのSQL文であるDDLを取得する。
$ mysqldump -u katryo -p --no-data mydb > dump.sql
で、dump.sqlというDDLを生成する。
で、Data::Generator::FromDDLをシェルから扱えるdatagen_from_ddlを使って、
$ datagen_from_ddl --num=100000 dump.sql | mysql -u katryo -p mydb
すると、MySQL内のmydbの各テーブルに、100000レコード/1テーブル のデータが入る。
8GBのMacBookAirで、26テーブルで100000レコードで実行すると30秒かかった。
Data::Generator::FromDDLの素晴らしさ
Data::Generator::FromDDLは、DDLをパースして自動的にダミーデータのinsert文を出力してくれる。
さきほどの例を、3レコード/1テーブルで行ってみよう。出力を見やすくするために --pretty のオプションもつけてみる。
$ datagen_from_ddl --num=3 --pretty dump.sql
をすると、以下のような文が出力される。ちなみに、レシピサイトを作っているとする。
INSERT IGNORE INTO `foodstuffs` (`foodstuff_id`,`name`,`created_at`) VALUES (1,'name1',-1429218243),(2,'name2',99576727),(3,'name3',-1565718941);
INSERT IGNORE INTO `request_ids` (`request_id`) VALUES (1),(2),(3);
INSERT IGNORE INTO `tags` (`tag_id`,`name`,`created_at`) VALUES (1,'name1',2542618628),(2,'name2',3291009850),(3,'name3',1095817358);
INSERT IGNORE INTO `users` (`user_id`,`nickname`,`family_name`,`given_name`,`email`,`salt_hashed_password`,`gender`,`created_at`,`updated_at`) VALUES (1,'nickname1','family_name1','given_name1','email1','salt_hashed_password1',-22,2261241673,2135291890),(2,'nickname2','family_name2','given_name2','email2','salt_hashed_password2',114,2162413120,440265079),
...(以下略)
こんな風に、create table文から、適当な値を入れてinsert文を作ってくれる。テーブル同士の関係、制約を守りながら大量のデータを入れるのに便利。
テーブルごとに入れるレコードの数を変えるとき
現実のアプリケーションでは、テーブルごとにレコード数はかなり異なる。なので、ダミーデータもテーブルごとの目的にあわせて、その量を変えるべきだ。Data::Generator::FromDDLにはその仕組みがある。
コマンドラインツールのdatagen_from_ddlではそこまで複雑な仕事をさせられないので、自分でスクリプトを書くといい。
# !/usr/bin/env perl
use strict;
use warnings;
use utf8;
use autodie;
use Data::Dumper;
use Data::Generator::FromDDL;
open my $fh, '<', $ARGV[0] or die "Could not open ddl: $!";
my $ddl = '';
foreach my $line (<$fh>) {
$ddl .= $line;
}
close $fh;
my $generator = Data::Generator::FromDDL->new(
{ ddl => $ddl,
parser => 'mysql',
}
);
my $num = {
all => 1000000,
tables => {
followings => 5000000,
likes => 20000000,
}
};
$generator->generate($num);
こんな感じに、$ARGV[0]でddlファイル(mysqldump --no-dataで作ったもの)を指定するようなスクリプトを書いて、
$ perl dummy_into_mysql.pl dump.sql | mysql -u katryo -p mydb
とすると、followingsには5000000件、likesには20000000件、それ以外には1000000件のレコードが入る。